/////////////////////////////////////////////////////////////////////////////// | |
// dynamic.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_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 | |
#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 | |
// MS compatible compilers support #pragma once | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include <vector> | |
#include <utility> | |
#include <algorithm> | |
#include <boost/assert.hpp> | |
#include <boost/mpl/int.hpp> | |
#include <boost/mpl/assert.hpp> | |
#include <boost/throw_exception.hpp> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/xpressive/detail/detail_fwd.hpp> | |
#include <boost/xpressive/detail/core/quant_style.hpp> | |
#include <boost/xpressive/detail/dynamic/matchable.hpp> | |
#include <boost/xpressive/detail/dynamic/sequence.hpp> | |
#include <boost/xpressive/detail/core/icase.hpp> | |
namespace boost { namespace xpressive { namespace detail | |
{ | |
/////////////////////////////////////////////////////////////////////////////// | |
// invalid_xpression | |
template<typename BidiIter> | |
struct invalid_xpression | |
: matchable_ex<BidiIter> | |
{ | |
invalid_xpression() | |
: matchable_ex<BidiIter>() | |
{ | |
intrusive_ptr_add_ref(this); // keep alive forever | |
} | |
bool match(match_state<BidiIter> &) const | |
{ | |
BOOST_ASSERT(false); | |
return false; | |
} | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// get_invalid_xpression | |
template<typename BidiIter> | |
inline shared_matchable<BidiIter> const &get_invalid_xpression() | |
{ | |
static invalid_xpression<BidiIter> const invalid_xpr; | |
static intrusive_ptr<matchable_ex<BidiIter> const> const invalid_ptr(&invalid_xpr); | |
static shared_matchable<BidiIter> const invalid_matchable(invalid_ptr); | |
return invalid_matchable; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// dynamic_xpression | |
template<typename Matcher, typename BidiIter> | |
struct dynamic_xpression | |
: Matcher | |
, matchable_ex<BidiIter> | |
{ | |
typedef typename iterator_value<BidiIter>::type char_type; | |
dynamic_xpression(Matcher const &matcher = Matcher()) | |
: Matcher(matcher) | |
, next_(get_invalid_xpression<BidiIter>()) | |
{ | |
} | |
virtual bool match(match_state<BidiIter> &state) const | |
{ | |
return this->Matcher::match(state, *this->next_.matchable()); | |
} | |
virtual void link(xpression_linker<char_type> &linker) const | |
{ | |
linker.accept(*static_cast<Matcher const *>(this), this->next_.matchable().get()); | |
this->next_.link(linker); | |
} | |
virtual void peek(xpression_peeker<char_type> &peeker) const | |
{ | |
this->peek_next_(peeker.accept(*static_cast<Matcher const *>(this)), peeker); | |
} | |
virtual void repeat(quant_spec const &spec, sequence<BidiIter> &seq) const | |
{ | |
this->repeat_(spec, seq, quant_type<Matcher>(), is_same<Matcher, mark_begin_matcher>()); | |
} | |
private: | |
friend struct sequence<BidiIter>; | |
void peek_next_(mpl::true_, xpression_peeker<char_type> &peeker) const | |
{ | |
this->next_.peek(peeker); | |
} | |
void peek_next_(mpl::false_, xpression_peeker<char_type> &) const | |
{ | |
// no-op | |
} | |
void repeat_(quant_spec const &spec, sequence<BidiIter> &seq, mpl::int_<quant_none>, mpl::false_) const | |
{ | |
if(quant_none == seq.quant()) | |
{ | |
BOOST_THROW_EXCEPTION( | |
regex_error(regex_constants::error_badrepeat, "expression cannot be quantified") | |
); | |
} | |
else | |
{ | |
this->repeat_(spec, seq, mpl::int_<quant_variable_width>(), mpl::false_()); | |
} | |
} | |
void repeat_(quant_spec const &spec, sequence<BidiIter> &seq, mpl::int_<quant_fixed_width>, mpl::false_) const | |
{ | |
if(this->next_ == get_invalid_xpression<BidiIter>()) | |
{ | |
make_simple_repeat(spec, seq, matcher_wrapper<Matcher>(*this)); | |
} | |
else | |
{ | |
this->repeat_(spec, seq, mpl::int_<quant_variable_width>(), mpl::false_()); | |
} | |
} | |
void repeat_(quant_spec const &spec, sequence<BidiIter> &seq, mpl::int_<quant_variable_width>, mpl::false_) const | |
{ | |
if(!is_unknown(seq.width()) && seq.pure()) | |
{ | |
make_simple_repeat(spec, seq); | |
} | |
else | |
{ | |
make_repeat(spec, seq); | |
} | |
} | |
void repeat_(quant_spec const &spec, sequence<BidiIter> &seq, mpl::int_<quant_fixed_width>, mpl::true_) const | |
{ | |
make_repeat(spec, seq, this->mark_number_); | |
} | |
shared_matchable<BidiIter> next_; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// make_dynamic | |
template<typename BidiIter, typename Matcher> | |
inline sequence<BidiIter> make_dynamic(Matcher const &matcher) | |
{ | |
typedef dynamic_xpression<Matcher, BidiIter> xpression_type; | |
intrusive_ptr<xpression_type> xpr(new xpression_type(matcher)); | |
return sequence<BidiIter>(xpr); | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// alternates_vector | |
template<typename BidiIter> | |
struct alternates_vector | |
: std::vector<shared_matchable<BidiIter> > | |
{ | |
BOOST_STATIC_CONSTANT(std::size_t, width = unknown_width::value); | |
BOOST_STATIC_CONSTANT(bool, pure = false); | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// matcher_wrapper | |
template<typename Matcher> | |
struct matcher_wrapper | |
: Matcher | |
{ | |
matcher_wrapper(Matcher const &matcher = Matcher()) | |
: Matcher(matcher) | |
{ | |
} | |
template<typename BidiIter> | |
bool match(match_state<BidiIter> &state) const | |
{ | |
return this->Matcher::match(state, matcher_wrapper<true_matcher>()); | |
} | |
template<typename Char> | |
void link(xpression_linker<Char> &linker) const | |
{ | |
linker.accept(*static_cast<Matcher const *>(this), 0); | |
} | |
template<typename Char> | |
void peek(xpression_peeker<Char> &peeker) const | |
{ | |
peeker.accept(*static_cast<Matcher const *>(this)); | |
} | |
}; | |
////////////////////////////////////////////////////////////////////////// | |
// make_simple_repeat | |
template<typename BidiIter, typename Xpr> | |
inline void | |
make_simple_repeat(quant_spec const &spec, sequence<BidiIter> &seq, Xpr const &xpr) | |
{ | |
if(spec.greedy_) | |
{ | |
simple_repeat_matcher<Xpr, mpl::true_> quant(xpr, spec.min_, spec.max_, seq.width().value()); | |
seq = make_dynamic<BidiIter>(quant); | |
} | |
else | |
{ | |
simple_repeat_matcher<Xpr, mpl::false_> quant(xpr, spec.min_, spec.max_, seq.width().value()); | |
seq = make_dynamic<BidiIter>(quant); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////// | |
// make_simple_repeat | |
template<typename BidiIter> | |
inline void | |
make_simple_repeat(quant_spec const &spec, sequence<BidiIter> &seq) | |
{ | |
seq += make_dynamic<BidiIter>(true_matcher()); | |
make_simple_repeat(spec, seq, seq.xpr()); | |
} | |
////////////////////////////////////////////////////////////////////////// | |
// make_optional | |
template<typename BidiIter> | |
inline void | |
make_optional(quant_spec const &spec, sequence<BidiIter> &seq) | |
{ | |
typedef shared_matchable<BidiIter> xpr_type; | |
seq += make_dynamic<BidiIter>(alternate_end_matcher()); | |
if(spec.greedy_) | |
{ | |
optional_matcher<xpr_type, mpl::true_> opt(seq.xpr()); | |
seq = make_dynamic<BidiIter>(opt); | |
} | |
else | |
{ | |
optional_matcher<xpr_type, mpl::false_> opt(seq.xpr()); | |
seq = make_dynamic<BidiIter>(opt); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////// | |
// make_optional | |
template<typename BidiIter> | |
inline void | |
make_optional(quant_spec const &spec, sequence<BidiIter> &seq, int mark_nbr) | |
{ | |
typedef shared_matchable<BidiIter> xpr_type; | |
seq += make_dynamic<BidiIter>(alternate_end_matcher()); | |
if(spec.greedy_) | |
{ | |
optional_mark_matcher<xpr_type, mpl::true_> opt(seq.xpr(), mark_nbr); | |
seq = make_dynamic<BidiIter>(opt); | |
} | |
else | |
{ | |
optional_mark_matcher<xpr_type, mpl::false_> opt(seq.xpr(), mark_nbr); | |
seq = make_dynamic<BidiIter>(opt); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////// | |
// make_repeat | |
template<typename BidiIter> | |
inline void | |
make_repeat(quant_spec const &spec, sequence<BidiIter> &seq) | |
{ | |
// only bother creating a repeater if max is greater than one | |
if(1 < spec.max_) | |
{ | |
// create a hidden mark so this expression can be quantified | |
int mark_nbr = -static_cast<int>(++*spec.hidden_mark_count_); | |
seq = make_dynamic<BidiIter>(mark_begin_matcher(mark_nbr)) + seq | |
+ make_dynamic<BidiIter>(mark_end_matcher(mark_nbr)); | |
make_repeat(spec, seq, mark_nbr); | |
return; | |
} | |
// if min is 0, the repeat must be made optional | |
if(0 == spec.min_) | |
{ | |
make_optional(spec, seq); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////// | |
// make_repeat | |
template<typename BidiIter> | |
inline void | |
make_repeat(quant_spec const &spec, sequence<BidiIter> &seq, int mark_nbr) | |
{ | |
BOOST_ASSERT(spec.max_); // we should never get here if max is 0 | |
// only bother creating a repeater if max is greater than one | |
if(1 < spec.max_) | |
{ | |
// TODO: statically bind the repeat matchers to the mark matchers for better perf | |
unsigned int min = spec.min_ ? spec.min_ : 1U; | |
repeat_begin_matcher repeat_begin(mark_nbr); | |
if(spec.greedy_) | |
{ | |
repeat_end_matcher<mpl::true_> repeat_end(mark_nbr, min, spec.max_); | |
seq = make_dynamic<BidiIter>(repeat_begin) + seq | |
+ make_dynamic<BidiIter>(repeat_end); | |
} | |
else | |
{ | |
repeat_end_matcher<mpl::false_> repeat_end(mark_nbr, min, spec.max_); | |
seq = make_dynamic<BidiIter>(repeat_begin) + seq | |
+ make_dynamic<BidiIter>(repeat_end); | |
} | |
} | |
// if min is 0, the repeat must be made optional | |
if(0 == spec.min_) | |
{ | |
make_optional(spec, seq, mark_nbr); | |
} | |
} | |
}}} // namespace boost::xpressive::detail | |
#endif |