Skip to content

Instantly share code, notes, and snippets.

@cppljevans
Last active March 2, 2018 10:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cppljevans/a74ceee491c6c8fd6ff48311dbf50b29 to your computer and use it in GitHub Desktop.
Save cppljevans/a74ceee491c6c8fd6ff48311dbf50b29 to your computer and use it in GitHub Desktop.
spirit pr370
//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