#if (defined(_DEBUG) && !defined(MBLQI_DONT_DEBUG_RULES)) || defined(MBLQI_DEBUG_RULES)
# define MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) \
::mbl::debug_position( pdbg, pname, ppos )
# define MBL_QI_DEBUG_PARSER_( pdbg, pname, ppos ) MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) >>
# define _MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) >> MBL_QI_DEBUG_PARSER( pdbg, pname, ppos )
#else
# define MBL_QI_DEBUG_PARSER( pdbg, pname, ppos )
# define MBL_QI_DEBUG_PARSER_( pdbg, pname, ppos )
# define _MBL_QI_DEBUG_PARSER( pdbg, pname, ppos )
#endif
#define MBL_QI_DEBUG_MSG_START "<START>"
#define MBL_QI_DEBUG_MSG_END "<END>"
#define MBL_QI_DEBUG_PARSER_START( pdbg, pname ) MBL_QI_DEBUG_PARSER_( pdbg, pname, MBL_QI_DEBUG_MSG_START )
#define MBL_QI_DEBUG_PARSER_END( pdbg, pname ) _MBL_QI_DEBUG_PARSER( pdbg, pname, MBL_QI_DEBUG_MSG_END )
namespace mbl {
struct parser_debugger {
// could be virtual, but I want my type to be POD
bool (*report)( parser_debugger*, char const* parserName, char const* msg,
std::string const& pos );
};
static bool report_impl_base( parser_debugger*, char const* pname,
char const* msg, std::string const& pos, std::ostream& os, size_t line_size,
size_t pname_len, size_t msg_len )
{
size_t n = strlen( msg );
std::string pad;
if( n < msg_len ) pad.assign( (msg_len - n) / 2, ' ' );
std::ios_base::fmtflags f = os.flags();
os.flags( f | std::ios_base::left );
os << std::setw(pname_len) << pname
<< '(' << pad << std::setw(msg_len - pad.size()) << msg << "): ";
os.flags( f );
bool sp = false;
std::size_t cnt = (std::max<size_t>)(strlen(pname), pname_len) +
(std::max<size_t>)(n, msg_len) + 4;
for( auto i = pos.begin(); i != pos.end(); i++ ) {
char c = *i;
if( ::isspace(c) ) {
if( sp ) continue;
sp = true;
c = ' ';
} else {
sp = false;
}
if( cnt++ >= line_size ) {
os << "...";
break;
} else {
os << c;
}
}
os << std::endl;
return true;
}
static bool report_impl( parser_debugger* pd, char const* pname, char const* msg,
std::string const& pos )
{
return report_impl_base( pd, pname, msg, pos, std::clog, 100, 20, 10 );
}
static parser_debugger& default_parser_debugger() {
static parser_debugger res = { {&report_impl} };
return res;
}
BOOST_SPIRIT_TERMINAL_EX( debug_position );
struct debug_position_parser : qi::primitive_parser<debug_position_parser> {
debug_position_parser( parser_debugger* pdebugger, char const* pname, char const* msg )
: pdebugger_( pdebugger ), pname_( pname ), msg_( msg ) {}
template< typename ContextT, typename IteratorT >
struct attribute { typedef spirit::unused_type type; };
template< typename IteratorT, typename ContextT, typename SkipperT, typename AttributeT >
bool parse( IteratorT& first, IteratorT const& last, ContextT& context,
SkipperT const& skipper, AttributeT& attr ) const
{
typedef std::iterator_traits<IteratorT>::value_type char_type;
typedef std::basic_string<char_type> string_type;
qi::skip_over( first, last, skipper );
if( !pdebugger_ ) return true;
pdebugger_->report( pdebugger_, pname_, msg_,
boost::locale::conv::utf_to_utf<char>(string_type(first, last)) );
return true;
}
template< class ContextT >
spirit::info what( ContextT& context ) const {
return spirit::info( "debug_position", expression_ );
}
char const* pname_;
char const* msg_;
parser_debugger* pdebugger_;
};
}
namespace boost { namespace spirit {
template<>
struct use_terminal<qi::domain, mbl::tag::debug_position>
: mpl::true_ {}; // enable debug_position
template< typename A0, typename A1, typename A2 >
struct use_terminal<qi::domain,
terminal_ex<mbl::tag::debug_position, fusion::vector3<A0, A1, A2> >
> : is_convertible<A0, mbl::parser_debugger*> {}; // enable debug_position( debugger, name, pos )
template<>
struct use_lazy_terminal<qi::domain, mbl::tag::debug_position, 3 /*arity*/>
: mpl::true_ {}; // enable lazy support for debug_position
namespace qi {
template< typename A0, typename A1, typename A2, typename ModifiersT >
struct make_primitive<
terminal_ex<mbl::tag::debug_position, fusion::vector3<A0, A1, A2> >, ModifiersT >
{
typedef mbl::debug_position_parser result_type;
template< typename TerminalT >
result_type operator()( TerminalT const& term, unused_type ) const {
return result_type( fusion::at_c<0>(term.args),
fusion::at_c<1>(term.args), fusion::at_c<2>(term.args) );
}
};
}
} }