/////////////////////////////////////////////////////////////////////////////// // 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) # 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