You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
8.4 KiB
326 lines
8.4 KiB
3 years ago
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// linker.hpp
|
||
|
//
|
||
|
// Copyright 2008 Eric Niebler. Distributed under the Boost
|
||
|
// Software License, Version 1.0. (See accompanying file
|
||
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
||
|
#ifndef BOOST_XPRESSIVE_DETAIL_CORE_LINKER_HPP_EAN_10_04_2005
|
||
|
#define BOOST_XPRESSIVE_DETAIL_CORE_LINKER_HPP_EAN_10_04_2005
|
||
|
|
||
|
// MS compatible compilers support #pragma once
|
||
|
#if defined(_MSC_VER)
|
||
|
# pragma once
|
||
|
#endif
|
||
|
|
||
|
#include <boost/config.hpp>
|
||
|
#ifndef BOOST_NO_STD_LOCALE
|
||
|
# include <locale>
|
||
|
#endif
|
||
|
#include <stack>
|
||
|
#include <limits>
|
||
|
#include <typeinfo>
|
||
|
#include <boost/shared_ptr.hpp>
|
||
|
#include <boost/type_traits/is_same.hpp>
|
||
|
#include <boost/version.hpp>
|
||
|
|
||
|
#if BOOST_VERSION >= 103500
|
||
|
# include <boost/fusion/include/for_each.hpp>
|
||
|
#else
|
||
|
# include <boost/spirit/fusion/algorithm/for_each.hpp>
|
||
|
#endif
|
||
|
|
||
|
#include <boost/xpressive/detail/detail_fwd.hpp>
|
||
|
#include <boost/xpressive/detail/dynamic/matchable.hpp>
|
||
|
#include <boost/xpressive/detail/core/matchers.hpp>
|
||
|
#include <boost/xpressive/detail/core/peeker.hpp>
|
||
|
#include <boost/xpressive/detail/utility/never_true.hpp>
|
||
|
|
||
|
namespace boost { namespace xpressive { namespace detail
|
||
|
{
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// icase_modifier
|
||
|
//
|
||
|
// wrapped by the modifier<> template and inserted into the xpression
|
||
|
// template with the icase() helper function. icase_modifier morphs
|
||
|
// a case-sensitive visitor into a case-insensitive visitor, which
|
||
|
// causes all matchers visited to become case-insensitive.
|
||
|
//
|
||
|
struct icase_modifier
|
||
|
{
|
||
|
template<typename Visitor>
|
||
|
struct apply {};
|
||
|
|
||
|
template<typename BidiIter, typename ICase, typename Traits>
|
||
|
struct apply<xpression_visitor<BidiIter, ICase, Traits> >
|
||
|
{
|
||
|
typedef xpression_visitor<BidiIter, mpl::true_, Traits> type;
|
||
|
};
|
||
|
|
||
|
template<typename Visitor>
|
||
|
static typename apply<Visitor>::type
|
||
|
call(Visitor &visitor)
|
||
|
{
|
||
|
return typename apply<Visitor>::type(visitor.traits(), visitor.self());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// regex_traits_type : wrap a locale in the appropriate regex_traits
|
||
|
//
|
||
|
template<typename Locale, typename BidiIter>
|
||
|
struct regex_traits_type
|
||
|
{
|
||
|
#ifndef BOOST_NO_STD_LOCALE
|
||
|
|
||
|
typedef typename iterator_value<BidiIter>::type char_type;
|
||
|
|
||
|
// if Locale is std::locale, wrap it in a cpp_regex_traits<Char>
|
||
|
typedef typename mpl::if_c
|
||
|
<
|
||
|
is_same<Locale, std::locale>::value
|
||
|
, cpp_regex_traits<char_type>
|
||
|
, Locale
|
||
|
>::type type;
|
||
|
|
||
|
#else
|
||
|
|
||
|
typedef Locale type;
|
||
|
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// locale_modifier
|
||
|
//
|
||
|
// wrapped by the modifier<> template and inserted into the xpression
|
||
|
// template with the imbue() helper function. Causes a sub-xpression to
|
||
|
// use the specified Locale
|
||
|
//
|
||
|
template<typename Locale>
|
||
|
struct locale_modifier
|
||
|
{
|
||
|
typedef Locale locale_type;
|
||
|
|
||
|
locale_modifier(Locale const &loc)
|
||
|
: loc_(loc)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template<typename Visitor>
|
||
|
struct apply {};
|
||
|
|
||
|
template<typename BidiIter, typename ICase, typename OtherTraits>
|
||
|
struct apply<xpression_visitor<BidiIter, ICase, OtherTraits> >
|
||
|
{
|
||
|
typedef typename regex_traits_type<Locale, BidiIter>::type traits_type;
|
||
|
typedef xpression_visitor<BidiIter, ICase, traits_type> type;
|
||
|
};
|
||
|
|
||
|
template<typename Visitor>
|
||
|
typename apply<Visitor>::type
|
||
|
call(Visitor &visitor) const
|
||
|
{
|
||
|
return typename apply<Visitor>::type(this->loc_, visitor.self());
|
||
|
}
|
||
|
|
||
|
Locale getloc() const
|
||
|
{
|
||
|
return this->loc_;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
Locale loc_;
|
||
|
};
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// xpression_linker
|
||
|
//
|
||
|
template<typename Char>
|
||
|
struct xpression_linker
|
||
|
{
|
||
|
template<typename Traits>
|
||
|
explicit xpression_linker(Traits const &tr)
|
||
|
: back_stack_()
|
||
|
, traits_(&tr)
|
||
|
, traits_type_(&typeid(Traits))
|
||
|
, has_backrefs_(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template<typename Matcher>
|
||
|
void accept(Matcher const &, void const *)
|
||
|
{
|
||
|
// no-op
|
||
|
}
|
||
|
|
||
|
template<typename Traits, typename ICase>
|
||
|
void accept(mark_matcher<Traits, ICase> const &, void const *)
|
||
|
{
|
||
|
this->has_backrefs_ = true;
|
||
|
}
|
||
|
|
||
|
template<typename Action>
|
||
|
void accept(action_matcher<Action> const &, void const *)
|
||
|
{
|
||
|
this->has_backrefs_ = true;
|
||
|
}
|
||
|
|
||
|
template<typename Predicate>
|
||
|
void accept(predicate_matcher<Predicate> const &, void const *)
|
||
|
{
|
||
|
this->has_backrefs_ = true;
|
||
|
}
|
||
|
|
||
|
void accept(repeat_begin_matcher const &, void const *next)
|
||
|
{
|
||
|
this->back_stack_.push(next);
|
||
|
}
|
||
|
|
||
|
template<typename Greedy>
|
||
|
void accept(repeat_end_matcher<Greedy> const &matcher, void const *)
|
||
|
{
|
||
|
matcher.back_ = this->back_stack_.top();
|
||
|
this->back_stack_.pop();
|
||
|
}
|
||
|
|
||
|
template<typename Alternates, typename Traits>
|
||
|
void accept(alternate_matcher<Alternates, Traits> const &matcher, void const *next)
|
||
|
{
|
||
|
xpression_peeker<Char> peeker(matcher.bset_, this->get_traits<Traits>());
|
||
|
this->alt_link(matcher.alternates_, next, &peeker);
|
||
|
}
|
||
|
|
||
|
void accept(alternate_end_matcher const &matcher, void const *)
|
||
|
{
|
||
|
matcher.back_ = this->back_stack_.top();
|
||
|
this->back_stack_.pop();
|
||
|
}
|
||
|
|
||
|
template<typename Xpr, typename Greedy>
|
||
|
void accept(optional_matcher<Xpr, Greedy> const &matcher, void const *next)
|
||
|
{
|
||
|
this->back_stack_.push(next);
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
template<typename Xpr, typename Greedy>
|
||
|
void accept(optional_mark_matcher<Xpr, Greedy> const &matcher, void const *next)
|
||
|
{
|
||
|
this->back_stack_.push(next);
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
template<typename Xpr>
|
||
|
void accept(keeper_matcher<Xpr> const &matcher, void const *)
|
||
|
{
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
template<typename Xpr>
|
||
|
void accept(lookahead_matcher<Xpr> const &matcher, void const *)
|
||
|
{
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
template<typename Xpr>
|
||
|
void accept(lookbehind_matcher<Xpr> const &matcher, void const *)
|
||
|
{
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
template<typename Xpr, typename Greedy>
|
||
|
void accept(simple_repeat_matcher<Xpr, Greedy> const &matcher, void const *)
|
||
|
{
|
||
|
matcher.xpr_.link(*this);
|
||
|
}
|
||
|
|
||
|
// accessors
|
||
|
bool has_backrefs() const
|
||
|
{
|
||
|
return this->has_backrefs_;
|
||
|
}
|
||
|
|
||
|
// for use by alt_link_pred below
|
||
|
template<typename Xpr>
|
||
|
void alt_branch_link(Xpr const &xpr, void const *next, xpression_peeker<Char> *peeker)
|
||
|
{
|
||
|
this->back_stack_.push(next);
|
||
|
xpr.link(*this);
|
||
|
xpr.peek(*peeker);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// alt_link_pred
|
||
|
//
|
||
|
struct alt_link_pred
|
||
|
{
|
||
|
xpression_linker<Char> *linker_;
|
||
|
xpression_peeker<Char> *peeker_;
|
||
|
void const *next_;
|
||
|
|
||
|
alt_link_pred
|
||
|
(
|
||
|
xpression_linker<Char> *linker
|
||
|
, xpression_peeker<Char> *peeker
|
||
|
, void const *next
|
||
|
)
|
||
|
: linker_(linker)
|
||
|
, peeker_(peeker)
|
||
|
, next_(next)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template<typename Xpr>
|
||
|
void operator ()(Xpr const &xpr) const
|
||
|
{
|
||
|
this->linker_->alt_branch_link(xpr, this->next_, this->peeker_);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename BidiIter>
|
||
|
void alt_link
|
||
|
(
|
||
|
alternates_vector<BidiIter> const &alternates
|
||
|
, void const *next
|
||
|
, xpression_peeker<Char> *peeker
|
||
|
)
|
||
|
{
|
||
|
std::for_each(alternates.begin(), alternates.end(), alt_link_pred(this, peeker, next));
|
||
|
}
|
||
|
|
||
|
template<typename Alternates>
|
||
|
void alt_link
|
||
|
(
|
||
|
fusion::sequence_base<Alternates> const &alternates
|
||
|
, void const *next
|
||
|
, xpression_peeker<Char> *peeker
|
||
|
)
|
||
|
{
|
||
|
#if BOOST_VERSION >= 103500
|
||
|
fusion::for_each(alternates.derived(), alt_link_pred(this, peeker, next));
|
||
|
#else
|
||
|
fusion::for_each(alternates.cast(), alt_link_pred(this, peeker, next));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
template<typename Traits>
|
||
|
Traits const &get_traits() const
|
||
|
{
|
||
|
BOOST_ASSERT(*this->traits_type_ == typeid(Traits));
|
||
|
return *static_cast<Traits const *>(this->traits_);
|
||
|
}
|
||
|
|
||
|
std::stack<void const *> back_stack_;
|
||
|
void const *traits_;
|
||
|
std::type_info const *traits_type_;
|
||
|
bool has_backrefs_;
|
||
|
};
|
||
|
|
||
|
}}} // namespace boost::xpressive::detail
|
||
|
|
||
|
#endif
|