You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
337 lines
10 KiB
337 lines
10 KiB
/////////////////////////////////////////////////////////////////////////////// |
|
// 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
|
|
|