Last active
March 2, 2018 10:01
-
-
Save cppljevans/a74ceee491c6c8fd6ff48311dbf50b29 to your computer and use it in GitHub Desktop.
spirit pr370
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Purpose: | |
// Experiment with different methods for making code here: | |
// https://github.com/Kojoley/spirit/blob/8b76132c8ded0c63b8ecc7d1689627ae49d1fde9/include/boost/spirit/home/x3/operator/detail/sequence.hpp#L419 | |
// a little more modular and help to answer question about | |
// whether to use lamba's as posed by Joel here: | |
// https://github.com/boostorg/spirit/pull/370#issuecomment-369410876 | |
//Result: | |
// Works both when | |
// defined(USE_CONSTEXPR_IF_LAMBDA) | |
// and when | |
// !defined(USE_CONSTEXPR_IF_LAMBDA) | |
// Howver, when: | |
// defined(USE_CONSTEXPR_IF_LAMBDA) | |
// * The code is more modular: | |
// https://en.wikipedia.org/wiki/Modular_programming | |
// because all the code is within the function itself. | |
// * But, it may not be as portable because of the assumed | |
// lack of constexpr if's in some compilers. | |
// OTOH, when: | |
// !defined(USE_CONSTEXPR_IF_LAMBDA) | |
// * The code is *less* modular because the code is distributed | |
// beteen the struct with private call functions: | |
// parse_sequence_container | |
// and the actual function: | |
// parse_sequence(...,tratis::container_attirube), | |
// doing the calling. | |
// * is more portable because it doesn't depend on constexpr if. | |
//======== | |
#include <boost/mpl/bool.hpp> | |
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp> | |
#include <type_traits> | |
//#define USE_CONSTEXPR_IF_LAMBDA | |
#include <iostream> | |
template<typename Iterator> | |
void print_first2last(Iterator& first, Iterator const& last) | |
{ | |
Iterator now=first; | |
std::cout<<"first..last=\n"; | |
while(now != last) std::cout<<*now++; | |
std::cout<<".\n"; | |
} | |
template<typename Left, typename Right> | |
struct parser_binary | |
{ | |
using left_type=Left; | |
using right_type=Right; | |
left_type left; | |
right_type right; | |
}; | |
#ifndef SEQ_SIZE_DEFAULT | |
#define SEQ_SIZE_DEFAULT 1 | |
#endif | |
template<std::size_t Size=SEQ_SIZE_DEFAULT> | |
struct parser_nullary | |
{ | |
template <typename Iterator, typename Context | |
, typename RContext, typename Attribute> | |
bool parse( | |
Iterator& first, Iterator const& last | |
, Context const& context, RContext& rcontext, Attribute& attr)const | |
{ | |
std::cout<<"calling:parser.parse(first, last, context, rcontext, attr);\n"; | |
std::cout<<"parser_nullary::Size="<<Size<<"\n"; | |
++first; | |
return true; | |
} | |
}; | |
namespace boost { namespace spirit { namespace x3 { namespace detail | |
{ | |
template <typename Parser, typename Context, typename Enable = void> | |
struct sequence_size | |
{ | |
static int const value = SEQ_SIZE_DEFAULT; | |
}; | |
template <std::size_t Size, typename Context, typename Enable> | |
struct sequence_size<parser_nullary<Size>, Context, Enable> | |
{ | |
static int const value = Size; | |
}; | |
template <typename Parser, typename Iterator, typename Context | |
, typename RContext, typename Attribute> | |
bool parse_into_container( Parser const& parser | |
, Iterator& first, Iterator const& last | |
, Context const& context, RContext& rcontext, Attribute& attr) | |
{ | |
std::cout<<"calling:parse_into_container(parser, first, last, context, rcontext, attr);\n"; | |
return parser.parse(first,last,context,rcontext,attr); | |
} | |
#ifndef USE_CONSTEXPR_IF_LAMBDA | |
struct parse_sequence_container | |
{ | |
//The purpose of following friend declaration and subsequent private: | |
//access specifier are to increase code encapsulation: | |
// https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)#An_information-hiding_mechanism | |
//because only the friend function has access to the private call functions. | |
//================== | |
template <typename Parser, typename Iterator, typename Context | |
, typename RContext, typename Attribute> | |
friend | |
bool parse_sequence( | |
Parser const& parser , Iterator& first, Iterator const& last | |
, Context const& context, RContext& rcontext, Attribute& attr | |
, traits::container_attribute) | |
; | |
private: | |
template <typename _Parser, typename _Iterator, typename _Context | |
, typename R_Context, typename _Attribute> | |
static bool call( | |
_Parser const& parser | |
, _Iterator& first, _Iterator const& last, _Context const& context | |
, R_Context& rcontext, _Attribute& attr, mpl::true_) | |
{ | |
return parser.parse(first, last, context, rcontext, attr); | |
} | |
template <typename _Parser, typename _Iterator, typename _Context | |
, typename R_Context, typename _Attribute> | |
static bool call( | |
_Parser const& parser | |
, _Iterator& first, _Iterator const& last, _Context const& context | |
, R_Context& rcontext, _Attribute& attr, mpl::false_) | |
{ | |
return parse_into_container(parser, first, last, context, rcontext, attr); | |
} | |
}; | |
#endif//USE_CONSTEXPR_IF_LAMBDA | |
template <typename Parser, typename Iterator, typename Context | |
, typename RContext, typename Attribute> | |
bool parse_sequence( | |
Parser const& parser , Iterator& first, Iterator const& last | |
, Context const& context, RContext& rcontext, Attribute& attr | |
, traits::container_attribute) | |
{ | |
constexpr auto discriminator= | |
[](auto const& _parser) | |
{ | |
using _Parser=std::remove_const_t<std::remove_reference_t<decltype(_parser)>>; | |
using which_t = mpl::bool_<(sequence_size<_Parser, Context>::value > 1)>; | |
return which_t{}; | |
}; | |
//#define CONSTEXPR_DISCRIMINATOR_WORKAROUND | |
#ifdef CONSTEXPR_DISCRIMINATOR_WORKAROUND | |
//Compilers should really not make this workaround needed :( | |
#define DISCRIMINATOR(PARSER) decltype(discriminator(PARSER)){} | |
#else | |
//With clang, this causes error about needing a constant expression. | |
#define DISCRIMINATOR(PARSER) discriminator(PARSER) | |
#endif//CONSTEXPR_DISCRIMINATOR_WORKAROUND | |
#if defined(USE_CONSTEXPR_IF_LAMBDA) | |
auto parse_with= | |
[&](auto const& _parser) | |
{ | |
constexpr auto which_v = DISCRIMINATOR(_parser); | |
if(which_v) | |
return _parser.parse(first,last,context,rcontext,attr); | |
else | |
return parse_into_container(_parser,first,last,context,rcontext,attr); | |
}; | |
#else | |
auto parse_with = | |
[&](auto const& _parser) | |
{ | |
constexpr auto which_v = DISCRIMINATOR(_parser); | |
return parse_sequence_container::call | |
(_parser,first,last,context,rcontext,attr,which_v); | |
}; | |
#endif//defined(USE_CONSTEXPR_IF_LAMBDA) | |
#undef DISCRIMINATOR | |
Iterator save = first; | |
if (parse_with(parser.left) && parse_with(parser.right)) | |
return true; | |
first = save; | |
return false; | |
} | |
}}}} | |
namespace x3 = boost::spirit::x3; | |
enum e_dummy | |
{ e_context | |
, e_rcontext | |
, e_attr | |
}; | |
template<e_dummy E> | |
struct t_dummy{}; | |
#include <string> | |
int main() | |
{ | |
std::cout<<"USE_CONSTEXPR_IF_LAMBDA is " | |
#ifdef USE_CONSTEXPR_IF_LAMBDA | |
<<"yes " | |
#else | |
<<"not " | |
#endif | |
<<"defined.\n"; | |
std::string input="1234567890"; | |
auto grammar=parser_binary<parser_nullary<>,parser_nullary<2>>{}; | |
t_dummy<e_context> v_context; | |
t_dummy<e_rcontext> v_rcontext; | |
t_dummy<e_attr> v_attr; | |
auto first=input.begin(); | |
auto last=input.end(); | |
bool result= | |
x3::detail::parse_sequence | |
( grammar | |
, first | |
, last | |
, v_context | |
, v_rcontext | |
, v_attr | |
, x3::traits::container_attribute{} | |
); | |
std::cout<<"result="<<result<<"\n"; | |
print_first2last(first,last); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment