diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/xpressive | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/xpressive')
124 files changed, 25328 insertions, 0 deletions
diff --git a/boost/xpressive/basic_regex.hpp b/boost/xpressive/basic_regex.hpp new file mode 100644 index 0000000000..eedcd9a547 --- /dev/null +++ b/boost/xpressive/basic_regex.hpp @@ -0,0 +1,295 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file basic_regex.hpp +/// Contains the definition of the basic_regex\<\> class template and its +/// associated helper functions. +// +// 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_BASIC_REGEX_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_BASIC_REGEX_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/xpressive_fwd.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/core/regex_domain.hpp> + +// Doxygen can't handle proto :-( +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# include <boost/xpressive/detail/static/grammar.hpp> +# include <boost/proto/extends.hpp> +#endif + +#if BOOST_XPRESSIVE_HAS_MS_STACK_GUARD +# include <excpt.h> // for _exception_code() +# include <malloc.h> // for _resetstkoflw() +#endif + +namespace boost { namespace xpressive +{ + +namespace detail +{ + inline void throw_on_stack_error(bool stack_error) + { + BOOST_XPR_ENSURE_(!stack_error, regex_constants::error_stack, "Regex stack space exhausted"); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// basic_regex +// +/// \brief Class template basic_regex\<\> is a class for holding a compiled regular expression. +template<typename BidiIter> +struct basic_regex + : proto::extends< + proto::expr<proto::tag::terminal, proto::term<detail::tracking_ptr<detail::regex_impl<BidiIter> > >, 0> + , basic_regex<BidiIter> + , detail::regex_domain + > +{ +private: + typedef proto::expr<proto::tag::terminal, proto::term<detail::tracking_ptr<detail::regex_impl<BidiIter> > >, 0> pimpl_type; + typedef proto::extends<pimpl_type, basic_regex<BidiIter>, detail::regex_domain> base_type; + +public: + typedef BidiIter iterator_type; + typedef typename iterator_value<BidiIter>::type char_type; + // For compatibility with std::basic_regex + typedef typename iterator_value<BidiIter>::type value_type; + typedef typename detail::string_type<char_type>::type string_type; + typedef regex_constants::syntax_option_type flag_type; + + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, ECMAScript = regex_constants::ECMAScript); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, icase = regex_constants::icase_); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, nosubs = regex_constants::nosubs); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, optimize = regex_constants::optimize); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, collate = regex_constants::collate); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, single_line = regex_constants::single_line); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, not_dot_null = regex_constants::not_dot_null); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, not_dot_newline = regex_constants::not_dot_newline); + BOOST_STATIC_CONSTANT(regex_constants::syntax_option_type, ignore_white_space = regex_constants::ignore_white_space); + + /// \post regex_id() == 0 + /// \post mark_count() == 0 + basic_regex() + : base_type() + { + } + + /// \param that The basic_regex object to copy. + /// \post regex_id() == that.regex_id() + /// \post mark_count() == that.mark_count() + basic_regex(basic_regex<BidiIter> const &that) + : base_type(that) + { + } + + /// \param that The basic_regex object to copy. + /// \post regex_id() == that.regex_id() + /// \post mark_count() == that.mark_count() + /// \return *this + basic_regex<BidiIter> &operator =(basic_regex<BidiIter> const &that) + { + proto::value(*this) = proto::value(that); + return *this; + } + + /// Construct from a static regular expression. + /// + /// \param expr The static regular expression + /// \pre Expr is the type of a static regular expression. + /// \post regex_id() != 0 + /// \post mark_count() \>= 0 + template<typename Expr> + basic_regex(Expr const &expr) + : base_type() + { + BOOST_XPRESSIVE_CHECK_REGEX(Expr, char_type); + this->compile_(expr, is_valid_regex<Expr, char_type>()); + } + + /// Construct from a static regular expression. + /// + /// \param expr The static regular expression. + /// \pre Expr is the type of a static regular expression. + /// \post regex_id() != 0 + /// \post mark_count() \>= 0 + /// \throw std::bad_alloc on out of memory + /// \return *this + template<typename Expr> + basic_regex<BidiIter> &operator =(Expr const &expr) + { + BOOST_XPRESSIVE_CHECK_REGEX(Expr, char_type); + this->compile_(expr, is_valid_regex<Expr, char_type>()); + return *this; + } + + /// Returns the count of capturing sub-expressions in this regular expression + /// + std::size_t mark_count() const + { + return proto::value(*this) ? proto::value(*this)->mark_count_ : 0; + } + + /// Returns a token which uniquely identifies this regular expression. + /// + regex_id_type regex_id() const + { + return proto::value(*this) ? proto::value(*this)->xpr_.get() : 0; + } + + /// Swaps the contents of this basic_regex object with another. + /// + /// \param that The other basic_regex object. + /// \attention This is a shallow swap that does not do reference tracking. + /// If you embed a basic_regex object by reference in another + /// regular expression and then swap its contents with another + /// basic_regex object, the change will not be visible to the + /// enclosing regular expression. It is done this way to ensure + /// that swap() cannot throw. + /// \throw nothrow + void swap(basic_regex<BidiIter> &that) // throw() + { + proto::value(*this).swap(proto::value(that)); + } + + /// Factory method for building a regex object from a range of characters. + /// Equivalent to regex_compiler\< BidiIter \>().compile(begin, end, flags); + /// + /// \param begin The beginning of a range of characters representing the + /// regular expression to compile. + /// \param end The end of a range of characters representing the + /// regular expression to compile. + /// \param flags Optional bitmask that determines how the pat string is + /// interpreted. (See syntax_option_type.) + /// \return A basic_regex object corresponding to the regular expression + /// represented by the character range. + /// \pre [begin,end) is a valid range. + /// \pre The range of characters specified by [begin,end) contains a + /// valid string-based representation of a regular expression. + /// \throw regex_error when the range of characters has invalid regular + /// expression syntax. + template<typename InputIter> + static basic_regex<BidiIter> compile(InputIter begin, InputIter end, flag_type flags = regex_constants::ECMAScript) + { + return regex_compiler<BidiIter>().compile(begin, end, flags); + } + + /// \overload + /// + template<typename InputRange> + static basic_regex<BidiIter> compile(InputRange const &pat, flag_type flags = regex_constants::ECMAScript) + { + return regex_compiler<BidiIter>().compile(pat, flags); + } + + /// \overload + /// + static basic_regex<BidiIter> compile(char_type const *begin, flag_type flags = regex_constants::ECMAScript) + { + return regex_compiler<BidiIter>().compile(begin, flags); + } + + /// \overload + /// + static basic_regex<BidiIter> compile(char_type const *begin, std::size_t len, flag_type flags) + { + return regex_compiler<BidiIter>().compile(begin, len, flags); + } + +private: + friend struct detail::core_access<BidiIter>; + + // Avoid a common programming mistake. Construction from a string is + // ambiguous. It could mean: + // sregex rx = sregex::compile(str); // compile the string into a regex + // or + // sregex rx = as_xpr(str); // treat the string as a literal + // Since there is no easy way to disambiguate, it is disallowed. You must + // say what you mean. + + /// INTERNAL ONLY + basic_regex(char_type const *); + /// INTERNAL ONLY + basic_regex(string_type const &); + + /// INTERNAL ONLY + bool match_(detail::match_state<BidiIter> &state) const + { + #if BOOST_XPRESSIVE_HAS_MS_STACK_GUARD + bool success = false, stack_error = false; + __try + { + success = proto::value(*this)->xpr_->match(state); + } + __except(_exception_code() == 0xC00000FDUL) + { + stack_error = true; + _resetstkoflw(); + } + detail::throw_on_stack_error(stack_error); + return success; + #else + return proto::value(*this)->xpr_->match(state); + #endif + } + + // Compiles valid static regexes into a state machine. + /// INTERNAL ONLY + template<typename Expr> + void compile_(Expr const &expr, mpl::true_) + { + detail::static_compile(expr, proto::value(*this).get()); + } + + // No-op for invalid static regexes. + /// INTERNAL ONLY + template<typename Expr> + void compile_(Expr const &, mpl::false_) + { + } +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::ECMAScript; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::icase; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::nosubs; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::optimize; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::collate; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::single_line; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::not_dot_null; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::not_dot_newline; +template<typename BidiIter> regex_constants::syntax_option_type const basic_regex<BidiIter>::ignore_white_space; +#endif + +/////////////////////////////////////////////////////////////////////////////// +// swap +/// \brief Swaps the contents of two basic_regex objects. +/// \param left The first basic_regex object. +/// \param right The second basic_regex object. +/// \attention This is a shallow swap that does not do reference tracking. +/// If you embed a basic_regex object by reference in another +/// regular expression and then swap its contents with another +/// basic_regex object, the change will not be visible to the +/// enclosing regular expression. It is done this way to ensure +/// that swap() cannot throw. +/// \throw nothrow +template<typename BidiIter> +inline void swap(basic_regex<BidiIter> &left, basic_regex<BidiIter> &right) // throw() +{ + left.swap(right); +} + +}} // namespace boost::xpressive + +#endif // BOOST_XPRESSIVE_BASIC_REGEX_HPP_EAN_10_04_2005 diff --git a/boost/xpressive/detail/core/access.hpp b/boost/xpressive/detail/core/access.hpp new file mode 100644 index 0000000000..d984a432fa --- /dev/null +++ b/boost/xpressive/detail/core/access.hpp @@ -0,0 +1,132 @@ +/////////////////////////////////////////////////////////////////////////////// +// access.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_ACCESS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_ACCESS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <vector> +#include <boost/shared_ptr.hpp> +#include <boost/proto/traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/matchable.hpp> +#include <boost/xpressive/match_results.hpp> // for type_info_less + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// core_access +// +template<typename BidiIter> +struct core_access +{ + typedef typename iterator_value<BidiIter>::type char_type; + + static std::size_t get_hidden_mark_count(basic_regex<BidiIter> const &rex) + { + return proto::value(rex)->hidden_mark_count_; + } + + static bool match(basic_regex<BidiIter> const &rex, match_state<BidiIter> &state) + { + return rex.match_(state); + } + + static shared_ptr<detail::regex_impl<BidiIter> > const & + get_regex_impl(basic_regex<BidiIter> const &rex) + { + return proto::value(rex).get(); + } + + static void init_sub_match_vector + ( + sub_match_vector<BidiIter> &subs_vect + , sub_match_impl<BidiIter> *subs_ptr + , std::size_t size + ) + { + subs_vect.init_(subs_ptr, size); + } + + static void init_sub_match_vector + ( + sub_match_vector<BidiIter> &subs_vect + , sub_match_impl<BidiIter> *subs_ptr + , std::size_t size + , sub_match_vector<BidiIter> const &that + ) + { + subs_vect.init_(subs_ptr, size, that); + } + + static void init_match_results + ( + match_results<BidiIter> &what + , regex_id_type regex_id + , intrusive_ptr<traits<char_type> const> const &tr + , sub_match_impl<BidiIter> *sub_matches + , std::size_t size + , std::vector<named_mark<char_type> > const &named_marks + ) + { + what.init_(regex_id, tr, sub_matches, size, named_marks); + } + + static sub_match_vector<BidiIter> &get_sub_match_vector(match_results<BidiIter> &what) + { + return what.sub_matches_; + } + + static sub_match_impl<BidiIter> *get_sub_matches(sub_match_vector<BidiIter> &subs) + { + return subs.sub_matches_; + } + + static results_extras<BidiIter> &get_extras(match_results<BidiIter> &what) + { + return what.get_extras_(); + } + + static nested_results<BidiIter> &get_nested_results(match_results<BidiIter> &what) + { + return what.nested_results_; + } + + static action_args_type &get_action_args(match_results<BidiIter> &what) + { + return what.args_; + } + + static void set_prefix_suffix(match_results<BidiIter> &what, BidiIter begin, BidiIter end) + { + what.set_prefix_suffix_(begin, end); + } + + static void reset(match_results<BidiIter> &what) + { + what.reset_(); + } + + static void set_base(match_results<BidiIter> &what, BidiIter base) + { + what.set_base_(base); + } + + static BidiIter get_base(match_results<BidiIter> &what) + { + return *what.base_; + } +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/action.hpp b/boost/xpressive/detail/core/action.hpp new file mode 100644 index 0000000000..bb54ee5f74 --- /dev/null +++ b/boost/xpressive/detail/core/action.hpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// action.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_ACTION_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_ACTION_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/match_results.hpp> // for type_info_less + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // actionable + // + struct actionable + { + virtual ~actionable() {} + virtual void execute(action_args_type *) const {} + + actionable() + : next(0) + {} + + actionable const *next; + }; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/adaptor.hpp b/boost/xpressive/detail/core/adaptor.hpp new file mode 100644 index 0000000000..6afecf2f92 --- /dev/null +++ b/boost/xpressive/detail/core/adaptor.hpp @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////// +// adaptor.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_ADAPTOR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_ADAPTOR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/ref.hpp> +#include <boost/implicit_cast.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/matchable.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// xpression_adaptor +// +// wrap a static xpression in a matchable interface so it can be stored +// in and invoked from a basic_regex object. +template<typename Xpr, typename Base> +struct xpression_adaptor + : Base // either matchable or matchable_ex +{ + typedef typename Base::iterator_type iterator_type; + typedef typename iterator_value<iterator_type>::type char_type; + + Xpr xpr_; + + xpression_adaptor(Xpr const &xpr) + #if BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4)) \ + && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) + // Ugh, gcc has an optimizer bug which elides this c'tor call + // resulting in pure virtual function calls. + __attribute__((noinline)) + #endif + : xpr_(xpr) + { + } + + virtual bool match(match_state<iterator_type> &state) const + { + typedef typename boost::unwrap_reference<Xpr const>::type xpr_type; + return implicit_cast<xpr_type &>(this->xpr_).match(state); + } + + void link(xpression_linker<char_type> &linker) const + { + this->xpr_.link(linker); + } + + void peek(xpression_peeker<char_type> &peeker) const + { + this->xpr_.peek(peeker); + } + +private: + xpression_adaptor &operator =(xpression_adaptor const &); +}; + +/////////////////////////////////////////////////////////////////////////////// +// make_adaptor +// +template<typename Base, typename Xpr> +inline intrusive_ptr<Base const> make_adaptor(Xpr const &xpr) +{ + return intrusive_ptr<Base const>(new xpression_adaptor<Xpr, Base>(xpr)); +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/finder.hpp b/boost/xpressive/detail/core/finder.hpp new file mode 100644 index 0000000000..56c6422719 --- /dev/null +++ b/boost/xpressive/detail/core/finder.hpp @@ -0,0 +1,221 @@ +/// Contains the definition of the basic_regex\<\> class template and its associated helper functions. +// +// 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_FINDER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_FINDER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4189) // local variable is initialized but not referenced +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/utility/boyer_moore.hpp> +#include <boost/xpressive/detail/utility/hash_peek_bitset.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// boyer_moore_finder +// +template<typename BidiIter, typename Traits> +struct boyer_moore_finder + : finder<BidiIter> +{ + typedef typename iterator_value<BidiIter>::type char_type; + + boyer_moore_finder(char_type const *begin, char_type const *end, Traits const &tr, bool icase) + : bm_(begin, end, tr, icase) + { + } + + bool ok_for_partial_matches() const + { + return false; + } + + bool operator ()(match_state<BidiIter> &state) const + { + Traits const &tr = traits_cast<Traits>(state); + state.cur_ = this->bm_.find(state.cur_, state.end_, tr); + return state.cur_ != state.end_; + } + +private: + boyer_moore_finder(boyer_moore_finder const &); + boyer_moore_finder &operator =(boyer_moore_finder const &); + + boyer_moore<BidiIter, Traits> bm_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// hash_peek_finder +// +template<typename BidiIter, typename Traits> +struct hash_peek_finder + : finder<BidiIter> +{ + typedef typename iterator_value<BidiIter>::type char_type; + + hash_peek_finder(hash_peek_bitset<char_type> const &bset) + : bset_(bset) + { + } + + bool operator ()(match_state<BidiIter> &state) const + { + Traits const &tr = traits_cast<Traits>(state); + state.cur_ = (this->bset_.icase() + ? this->find_(state.cur_, state.end_, tr, mpl::true_()) + : this->find_(state.cur_, state.end_, tr, mpl::false_())); + return state.cur_ != state.end_; + } + +private: + hash_peek_finder(hash_peek_finder const &); + hash_peek_finder &operator =(hash_peek_finder const &); + + template<typename ICase> + BidiIter find_(BidiIter begin, BidiIter end, Traits const &tr, ICase) const + { + for(; begin != end && !this->bset_.test(*begin, tr, ICase()); ++begin) + ; + return begin; + } + + hash_peek_bitset<char_type> bset_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// line_start_finder +// +template<typename BidiIter, typename Traits, std::size_t Size = sizeof(typename iterator_value<BidiIter>::type)> +struct line_start_finder + : finder<BidiIter> +{ + typedef typename iterator_value<BidiIter>::type char_type; + typedef typename iterator_difference<BidiIter>::type diff_type; + typedef typename Traits::char_class_type char_class_type; + + line_start_finder(Traits const &tr) + : newline_(lookup_classname(tr, "newline")) + { + } + + bool operator ()(match_state<BidiIter> &state) const + { + if(state.bos() && state.flags_.match_bol_) + { + return true; + } + + Traits const &tr = traits_cast<Traits>(state); + BidiIter cur = state.cur_; + BidiIter const end = state.end_; + std::advance(cur, static_cast<diff_type>(-!state.bos())); + + for(; cur != end; ++cur) + { + if(tr.isctype(*cur, this->newline_)) + { + state.cur_ = ++cur; + return true; + } + } + + return false; + } + +private: + line_start_finder(line_start_finder const &); + line_start_finder &operator =(line_start_finder const &); + + char_class_type newline_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// line_start_finder +// +template<typename BidiIter, typename Traits> +struct line_start_finder<BidiIter, Traits, 1u> + : finder<BidiIter> +{ + typedef typename iterator_value<BidiIter>::type char_type; + typedef typename iterator_difference<BidiIter>::type diff_type; + typedef typename Traits::char_class_type char_class_type; + + line_start_finder(Traits const &tr) + { + char_class_type newline = lookup_classname(tr, "newline"); + for(int j = 0; j < 256; ++j) + { + this->bits_[j] = tr.isctype(static_cast<char_type>(static_cast<unsigned char>(j)), newline); + } + } + + bool operator ()(match_state<BidiIter> &state) const + { + if(state.bos() && state.flags_.match_bol_) + { + return true; + } + + BidiIter cur = state.cur_; + BidiIter const end = state.end_; + std::advance(cur, static_cast<diff_type>(-!state.bos())); + + for(; cur != end; ++cur) + { + if(this->bits_[static_cast<unsigned char>(*cur)]) + { + state.cur_ = ++cur; + return true; + } + } + + return false; + } + +private: + line_start_finder(line_start_finder const &); + line_start_finder &operator =(line_start_finder const &); + + bool bits_[256]; +}; + +/////////////////////////////////////////////////////////////////////////////// +// leading_simple_repeat_finder +// +template<typename BidiIter> +struct leading_simple_repeat_finder + : finder<BidiIter> +{ + leading_simple_repeat_finder() + : finder<BidiIter>() + {} + + bool operator ()(match_state<BidiIter> &state) const + { + state.cur_ = state.next_search_; + return true; + } + +private: + leading_simple_repeat_finder(leading_simple_repeat_finder const &); + leading_simple_repeat_finder &operator =(leading_simple_repeat_finder const &); +}; + +}}} + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/core/flow_control.hpp b/boost/xpressive/detail/core/flow_control.hpp new file mode 100644 index 0000000000..2ca5156525 --- /dev/null +++ b/boost/xpressive/detail/core/flow_control.hpp @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////// +// flow_control.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_FLOW_CONTROL_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_FLOW_CONTROL_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// push_context_match +// +template<typename BidiIter> +inline bool push_context_match +( + regex_impl<BidiIter> const &impl + , match_state<BidiIter> &state + , matchable<BidiIter> const &next +) +{ + // avoid infinite recursion + // BUGBUG this only catches direct infinite recursion, like sregex::compile("(?R)"), but + // not indirect infinite recursion where two rules invoke each other recursively. + if(state.is_active_regex(impl) && state.cur_ == state.sub_match(0).begin_) + { + return next.match(state); + } + + // save state + match_context<BidiIter> context = state.push_context(impl, next, context); + detail::ignore_unused(context); + + // match the nested regex and uninitialize the match context + // (reclaims the sub_match objects if necessary) + return state.pop_context(impl, impl.xpr_->match(state)); +} + +/////////////////////////////////////////////////////////////////////////////// +// pop_context_match +// +template<typename BidiIter> +inline bool pop_context_match(match_state<BidiIter> &state) +{ + // save state + // BUGBUG nested regex could have changed state.traits_ + match_context<BidiIter> &context(*state.context_.prev_context_); + state.swap_context(context); + + // Finished matching the nested regex; now match the rest of the enclosing regex + bool success = context.next_ptr_->match(state); + + // restore state + state.swap_context(context); + return success; +} + +}}} // namespace boost::xpressive::detail + +#endif + diff --git a/boost/xpressive/detail/core/icase.hpp b/boost/xpressive/detail/core/icase.hpp new file mode 100644 index 0000000000..2b2bdc8541 --- /dev/null +++ b/boost/xpressive/detail/core/icase.hpp @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// icase.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_ICASE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_ICASE_HPP_EAN_10_04_2005 + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/static/modifier.hpp> +#include <boost/xpressive/detail/core/linker.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive { namespace regex_constants +{ + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Makes a sub-expression case-insensitive. +/// +/// Use icase() to make a sub-expression case-insensitive. For instance, +/// "foo" >> icase(set['b'] >> "ar") will match "foo" exactly followed by +/// "bar" irrespective of case. +detail::modifier_op<detail::icase_modifier> const icase = {{}, regex_constants::icase_}; + +} // namespace regex_constants + +using regex_constants::icase; + +namespace detail +{ + inline void ignore_unused_icase() + { + detail::ignore_unused(icase); + } +} + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/detail/core/linker.hpp b/boost/xpressive/detail/core/linker.hpp new file mode 100644 index 0000000000..e87e26d125 --- /dev/null +++ b/boost/xpressive/detail/core/linker.hpp @@ -0,0 +1,325 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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) && (_MSC_VER >= 1020) +# 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 diff --git a/boost/xpressive/detail/core/list.hpp b/boost/xpressive/detail/core/list.hpp new file mode 100644 index 0000000000..f2135408ec --- /dev/null +++ b/boost/xpressive/detail/core/list.hpp @@ -0,0 +1,243 @@ +/////////////////////////////////////////////////////////////////////////////// +// list.hpp +// A simple implementation of std::list that allows incomplete +// types, does no dynamic allocation in the default constructor, +// and has a guarnteed O(1) splice. +// +// Copyright 2009 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_LIST_HPP_EAN_10_26_2009 +#define BOOST_XPRESSIVE_DETAIL_CORE_LIST_HPP_EAN_10_26_2009 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <cstddef> +#include <iterator> +#include <algorithm> +#include <boost/assert.hpp> +#include <boost/iterator/iterator_facade.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // list + // + template<typename T> + struct list + { + private: + struct node_base + { + node_base *_prev; + node_base *_next; + }; + + struct node : node_base + { + explicit node(T const &value) + : _value(value) + {} + + T _value; + }; + + node_base _sentry; + + template<typename Ref = T &> + struct list_iterator + : boost::iterator_facade<list_iterator<Ref>, T, std::bidirectional_iterator_tag, Ref> + { + list_iterator(list_iterator<> const &it) : _node(it._node) {} + explicit list_iterator(node_base *n = 0) : _node(n) {} + private: + friend struct list<T>; + friend class boost::iterator_core_access; + Ref dereference() const { return static_cast<node *>(_node)->_value; } + void increment() { _node = _node->_next; } + void decrement() { _node = _node->_prev; } + bool equal(list_iterator const &it) const { return _node == it._node; } + node_base *_node; + }; + + public: + typedef T *pointer; + typedef T const *const_pointer; + typedef T &reference; + typedef T const &const_reference; + typedef list_iterator<> iterator; + typedef list_iterator<T const &> const_iterator; + typedef std::size_t size_type; + + list() + { + _sentry._next = _sentry._prev = &_sentry; + } + + list(list const &that) + { + _sentry._next = _sentry._prev = &_sentry; + const_iterator it = that.begin(), e = that.end(); + for( ; it != e; ++it) + push_back(*it); + } + + list &operator =(list const &that) + { + list(that).swap(*this); + return *this; + } + + ~list() + { + clear(); + } + + void clear() + { + while(!empty()) + pop_front(); + } + + void swap(list &that) // throw() + { + list temp; + temp.splice(temp.begin(), that); // move that to temp + that.splice(that.begin(), *this); // move this to that + splice(begin(), temp); // move temp to this + } + + void push_front(T const &t) + { + node *new_node = new node(t); + + new_node->_next = _sentry._next; + new_node->_prev = &_sentry; + + _sentry._next->_prev = new_node; + _sentry._next = new_node; + } + + void push_back(T const &t) + { + node *new_node = new node(t); + + new_node->_next = &_sentry; + new_node->_prev = _sentry._prev; + + _sentry._prev->_next = new_node; + _sentry._prev = new_node; + } + + void pop_front() + { + BOOST_ASSERT(!empty()); + node *old_node = static_cast<node *>(_sentry._next); + _sentry._next = old_node->_next; + _sentry._next->_prev = &_sentry; + delete old_node; + } + + void pop_back() + { + BOOST_ASSERT(!empty()); + node *old_node = static_cast<node *>(_sentry._prev); + _sentry._prev = old_node->_prev; + _sentry._prev->_next = &_sentry; + delete old_node; + } + + bool empty() const + { + return _sentry._next == &_sentry; + } + + void splice(iterator it, list &x) + { + if(x.empty()) + return; + + x._sentry._prev->_next = it._node; + x._sentry._next->_prev = it._node->_prev; + + it._node->_prev->_next = x._sentry._next; + it._node->_prev = x._sentry._prev; + + x._sentry._prev = x._sentry._next = &x._sentry; + } + + void splice(iterator it, list &, iterator xit) + { + xit._node->_prev->_next = xit._node->_next; + xit._node->_next->_prev = xit._node->_prev; + + xit._node->_next = it._node; + xit._node->_prev = it._node->_prev; + + it._node->_prev = it._node->_prev->_next = xit._node; + } + + reference front() + { + BOOST_ASSERT(!empty()); + return static_cast<node *>(_sentry._next)->_value; + } + + const_reference front() const + { + BOOST_ASSERT(!empty()); + return static_cast<node *>(_sentry._next)->_value; + } + + reference back() + { + BOOST_ASSERT(!empty()); + return static_cast<node *>(_sentry._prev)->_value; + } + + const_reference back() const + { + BOOST_ASSERT(!empty()); + return static_cast<node *>(_sentry._prev)->_value; + } + + iterator begin() + { + return iterator(_sentry._next); + } + + const_iterator begin() const + { + return const_iterator(_sentry._next); + } + + iterator end() + { + return iterator(&_sentry); + } + + const_iterator end() const + { + return const_iterator(const_cast<node_base *>(&_sentry)); + } + + size_type size() const + { + return static_cast<size_type>(std::distance(begin(), end())); + } + }; + + template<typename T> + void swap(list<T> &lhs, list<T> &rhs) + { + lhs.swap(rhs); + } + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/matcher/action_matcher.hpp b/boost/xpressive/detail/core/matcher/action_matcher.hpp new file mode 100644 index 0000000000..37180112f5 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/action_matcher.hpp @@ -0,0 +1,501 @@ +/////////////////////////////////////////////////////////////////////////////// +// action_matcher.hpp +// +// Copyright 2008 Eric Niebler. +// Copyright 2008 David Jenkins. +// +// 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_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/version.hpp> +#include <boost/ref.hpp> +#include <boost/assert.hpp> +#include <boost/mpl/if.hpp> +#include <boost/throw_exception.hpp> +#include <boost/utility/result_of.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/action.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/context.hpp> +#include <boost/xpressive/match_results.hpp> // for type_info_less +#include <boost/xpressive/detail/static/transforms/as_action.hpp> // for 'read_attr' +#if BOOST_VERSION >= 103500 +# include <boost/proto/fusion.hpp> +# include <boost/fusion/include/transform_view.hpp> +# include <boost/fusion/include/invoke.hpp> +# include <boost/fusion/include/push_front.hpp> +# include <boost/fusion/include/pop_front.hpp> +#endif + +#if BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4510) // default constructor could not be generated +#pragma warning(disable : 4512) // assignment operator could not be generated +#pragma warning(disable : 4610) // can never be instantiated - user defined constructor required +#endif + +namespace boost { namespace xpressive { namespace detail +{ + + #if BOOST_VERSION >= 103500 + struct DataMember + : proto::mem_ptr<proto::_, proto::terminal<proto::_> > + {}; + + template<typename Expr, long N> + struct child_ + : remove_reference< + typename proto::result_of::child_c<Expr &, N>::type + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // mem_ptr_eval + // Rewrites expressions of the form x->*foo(a) into foo(x, a) and then + // evaluates them. + template<typename Expr, typename Context, bool IsDataMember = proto::matches<Expr, DataMember>::value> + struct mem_ptr_eval + { + typedef typename child_<Expr, 0>::type left_type; + typedef typename child_<Expr, 1>::type right_type; + + typedef + typename proto::result_of::value< + typename proto::result_of::child_c<right_type, 0>::type + >::type + function_type; + + typedef + fusion::transform_view< + typename fusion::result_of::push_front< + typename fusion::result_of::pop_front<right_type>::type const + , reference_wrapper<left_type> + >::type const + , proto::eval_fun<Context> + > + evaluated_args; + + typedef + typename fusion::result_of::invoke<function_type, evaluated_args>::type + result_type; + + result_type operator()(Expr &expr, Context &ctx) const + { + return fusion::invoke<function_type>( + proto::value(proto::child_c<0>(proto::right(expr))) + , evaluated_args( + fusion::push_front(fusion::pop_front(proto::right(expr)), boost::ref(proto::left(expr))) + , proto::eval_fun<Context>(ctx) + ) + ); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // mem_ptr_eval + // Rewrites expressions of the form x->*foo into foo(x) and then + // evaluates them. + template<typename Expr, typename Context> + struct mem_ptr_eval<Expr, Context, true> + { + typedef typename child_<Expr, 0>::type left_type; + typedef typename child_<Expr, 1>::type right_type; + + typedef + typename proto::result_of::value<right_type>::type + function_type; + + typedef typename boost::result_of< + function_type(typename proto::result_of::eval<left_type, Context>::type) + >::type result_type; + + result_type operator()(Expr &expr, Context &ctx) const + { + return proto::value(proto::right(expr))( + proto::eval(proto::left(expr), ctx) + ); + } + }; + #endif + + struct attr_with_default_tag + {}; + + template<typename T> + struct opt; + + /////////////////////////////////////////////////////////////////////////////// + // action_context + // + struct action_context + { + explicit action_context(action_args_type *action_args) + : action_args_(action_args) + {} + + action_args_type const &args() const + { + return *this->action_args_; + } + + // eval_terminal + template<typename Expr, typename Arg> + struct eval_terminal + : proto::default_eval<Expr, action_context const> + {}; + + template<typename Expr, typename Arg> + struct eval_terminal<Expr, reference_wrapper<Arg> > + { + typedef Arg &result_type; + result_type operator()(Expr &expr, action_context const &) const + { + return proto::value(expr).get(); + } + }; + + template<typename Expr, typename Arg> + struct eval_terminal<Expr, opt<Arg> > + { + typedef Arg const &result_type; + result_type operator()(Expr &expr, action_context const &) const + { + return proto::value(expr); + } + }; + + template<typename Expr, typename Type, typename Int> + struct eval_terminal<Expr, action_arg<Type, Int> > + { + typedef typename action_arg<Type, Int>::reference result_type; + result_type operator()(Expr &expr, action_context const &ctx) const + { + action_args_type::const_iterator where_ = ctx.args().find(&typeid(proto::value(expr))); + if(where_ == ctx.args().end()) + { + BOOST_THROW_EXCEPTION( + regex_error( + regex_constants::error_badarg + , "An argument to an action was unspecified" + ) + ); + } + return proto::value(expr).cast(where_->second); + } + }; + + // eval + template<typename Expr, typename Tag = typename Expr::proto_tag> + struct eval + : proto::default_eval<Expr, action_context const> + {}; + + template<typename Expr> + struct eval<Expr, proto::tag::terminal> + : eval_terminal<Expr, typename proto::result_of::value<Expr>::type> + {}; + + // Evaluate attributes like a1|42 + template<typename Expr> + struct eval<Expr, attr_with_default_tag> + { + typedef + typename proto::result_of::value< + typename proto::result_of::left< + typename proto::result_of::child< + Expr + >::type + >::type + >::type + temp_type; + + typedef typename temp_type::type result_type; + + result_type operator ()(Expr const &expr, action_context const &ctx) const + { + return proto::value(proto::left(proto::child(expr))).t_ + ? *proto::value(proto::left(proto::child(expr))).t_ + : proto::eval(proto::right(proto::child(expr)), ctx); + } + }; + + #if BOOST_VERSION >= 103500 + template<typename Expr> + struct eval<Expr, proto::tag::mem_ptr> + : mem_ptr_eval<Expr, action_context const> + {}; + #endif + + private: + action_args_type *action_args_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // action + // + template<typename Actor> + struct action + : actionable + { + action(Actor const &actor) + : actionable() + , actor_(actor) + { + } + + virtual void execute(action_args_type *action_args) const + { + action_context const ctx(action_args); + proto::eval(this->actor_, ctx); + } + + private: + Actor actor_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // subreg_transform + // + struct subreg_transform : proto::transform<subreg_transform> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::state state_type; + + typedef + typename proto::terminal<sub_match<typename state_type::iterator> >::type + result_type; + + result_type operator ()( + typename impl::expr_param + , typename impl::state_param state + , typename impl::data_param data + ) const + { + return result_type::make(state.sub_matches_[ data ]); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // mark_transform + // + struct mark_transform : proto::transform<mark_transform> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::state state_type; + typedef + typename proto::terminal<sub_match<typename state_type::iterator> >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param + ) const + { + return result_type::make(state.sub_matches_[ proto::value(expr).mark_number_ ]); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // opt + // + template<typename T> + struct opt + { + typedef T type; + typedef T const &reference; + + opt(T const *t) + : t_(t) + {} + + operator reference() const + { + BOOST_XPR_ENSURE_(0 != this->t_, regex_constants::error_badattr, "Use of uninitialized regex attribute"); + return *this->t_; + } + + T const *t_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // attr_transform + // + struct attr_transform : proto::transform<attr_transform> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + + typedef + typename expr_type::proto_child0::matcher_type::value_type::second_type + attr_type; + + typedef + typename proto::terminal<opt<attr_type> >::type + result_type; + + result_type operator ()( + typename impl::expr_param + , typename impl::state_param state + , typename impl::data_param + ) const + { + int slot = typename expr_type::proto_child0::nbr_type(); + attr_type const *attr = static_cast<attr_type const *>(state.attr_context_.attr_slots_[slot-1]); + return result_type::make(opt<attr_type>(attr)); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // attr_with_default_transform + // + template<typename Grammar, typename Callable = proto::callable> + struct attr_with_default_transform : proto::transform<attr_with_default_transform<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::unary_expr< + attr_with_default_tag + , typename Grammar::template impl<Expr, State, Data>::result_type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + result_type that = { + typename Grammar::template impl<Expr, State, Data>()(expr, state, data) + }; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // by_ref_transform + // + struct by_ref_transform : proto::transform<by_ref_transform> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::result_of::value<typename impl::expr_param>::type + reference; + + typedef + typename proto::terminal<reference>::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param + ) const + { + return result_type::make(proto::value(expr)); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // BindActionArgs + // + struct BindActionArgs + : proto::or_< + proto::when<proto::terminal<any_matcher>, subreg_transform> + , proto::when<proto::terminal<mark_placeholder>, mark_transform> + , proto::when<proto::terminal<read_attr<proto::_, proto::_> >, attr_transform> + , proto::when<proto::terminal<proto::_>, by_ref_transform> + , proto::when< + proto::bitwise_or<proto::terminal<read_attr<proto::_, proto::_> >, BindActionArgs> + , attr_with_default_transform<proto::bitwise_or<attr_transform, BindActionArgs> > + > + , proto::otherwise<proto::nary_expr<proto::_, proto::vararg<BindActionArgs> > > + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // action_matcher + // + template<typename Actor> + struct action_matcher + : quant_style<quant_none, 0, false> + { + int sub_; + Actor actor_; + + action_matcher(Actor const &actor, int sub) + : sub_(sub) + , actor_(actor) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + // Bind the arguments + typedef + typename boost::result_of<BindActionArgs( + Actor const & + , match_state<BidiIter> & + , int const & + )>::type + action_type; + + action<action_type> actor(BindActionArgs()(this->actor_, state, this->sub_)); + + // Put the action in the action list + actionable const **action_list_tail = state.action_list_tail_; + *state.action_list_tail_ = &actor; + state.action_list_tail_ = &actor.next; + + // Match the rest of the pattern + if(next.match(state)) + { + return true; + } + + BOOST_ASSERT(0 == actor.next); + // remove action from list + *action_list_tail = 0; + state.action_list_tail_ = action_list_tail; + return false; + } + }; + +}}} + +#if BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/core/matcher/alternate_end_matcher.hpp b/boost/xpressive/detail/core/matcher/alternate_end_matcher.hpp new file mode 100644 index 0000000000..e0ae2ad283 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/alternate_end_matcher.hpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////// +// alternate_end_matcher.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_MATCHER_ALTERNATE_END_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ALTERNATE_END_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // alternate_end_matcher + // + struct alternate_end_matcher + : quant_style_assertion + { + mutable void const *back_; + + alternate_end_matcher() + : back_(0) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return next.pop_match(state, this->back_); + } + }; + +}}} + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/core/matcher/alternate_matcher.hpp b/boost/xpressive/detail/core/matcher/alternate_matcher.hpp new file mode 100644 index 0000000000..10e57ad6d1 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/alternate_matcher.hpp @@ -0,0 +1,132 @@ +/////////////////////////////////////////////////////////////////////////////// +// alternate_matcher.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_MATCHER_ALTERNATE_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ALTERNATE_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/version.hpp> +#if BOOST_VERSION <= 103200 +// WORKAROUND for Fusion bug in Boost 1.32 +namespace boost { namespace fusion +{ + namespace detail { struct iterator_root; } + using detail::iterator_root; +}} +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/dynamic/matchable.hpp> +#include <boost/xpressive/detail/utility/hash_peek_bitset.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> +#include <boost/xpressive/detail/utility/any.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // alt_match_pred + // + template<typename BidiIter, typename Next> + struct alt_match_pred + { + alt_match_pred(match_state<BidiIter> &state) + : state_(&state) + { + } + + template<typename Xpr> + bool operator ()(Xpr const &xpr) const + { + return xpr.BOOST_NESTED_TEMPLATE push_match<Next>(*this->state_); + } + + private: + match_state<BidiIter> *state_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // alt_match + // + template<typename BidiIter, typename Next> + inline bool alt_match + ( + alternates_vector<BidiIter> const &alts, match_state<BidiIter> &state, Next const & + ) + { + return detail::any(alts.begin(), alts.end(), alt_match_pred<BidiIter, Next>(state)); + } + + template<typename Head, typename Tail, typename BidiIter, typename Next> + inline bool alt_match + ( + alternates_list<Head, Tail> const &alts, match_state<BidiIter> &state, Next const & + ) + { + return fusion::any(alts, alt_match_pred<BidiIter, Next>(state)); + } + + /////////////////////////////////////////////////////////////////////////////// + // alternate_matcher + template<typename Alternates, typename Traits> + struct alternate_matcher + : quant_style< + Alternates::width != unknown_width::value && Alternates::pure ? quant_fixed_width : quant_variable_width + , Alternates::width + , Alternates::pure + > + { + typedef Alternates alternates_type; + typedef typename Traits::char_type char_type; + + Alternates alternates_; + mutable hash_peek_bitset<char_type> bset_; + + explicit alternate_matcher(Alternates const &alternates = Alternates()) + : alternates_(alternates) + , bset_() + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(!state.eos() && !this->can_match_(*state.cur_, traits_cast<Traits>(state))) + { + return false; + } + + return detail::alt_match(this->alternates_, state, next); + } + + detail::width get_width() const + { + // Only called when constructing static regexes, and this is a + // set of same-width alternates where the widths are known at compile + // time, as in: sregex rx = +(_ | 'a' | _n); + BOOST_MPL_ASSERT_RELATION(unknown_width::value, !=, Alternates::width); + return Alternates::width; + } + + private: + alternate_matcher &operator =(alternate_matcher const &); + + bool can_match_(char_type ch, Traits const &tr) const + { + return this->bset_.test(ch, tr); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/any_matcher.hpp b/boost/xpressive/detail/core/matcher/any_matcher.hpp new file mode 100644 index 0000000000..5c5336639f --- /dev/null +++ b/boost/xpressive/detail/core/matcher/any_matcher.hpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////// +// any_matcher.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_MATCHER_ANY_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ANY_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // any_matcher + // + struct any_matcher + { + BOOST_XPR_QUANT_STYLE(quant_fixed_width, 1, true) + + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + if(state.eos()) + { + return false; + } + + ++state.cur_; + if(next.match(state)) + { + return true; + } + + --state.cur_; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_bol_matcher.hpp b/boost/xpressive/detail/core/matcher/assert_bol_matcher.hpp new file mode 100644 index 0000000000..a7c0c8cdc5 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_bol_matcher.hpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_bol_matcher.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_MATCHER_ASSERT_BOL_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ASSERT_BOL_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/next_prior.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/matcher/assert_line_base.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // assert_bol_matcher + // + template<typename Traits> + struct assert_bol_matcher + : assert_line_base<Traits> + { + typedef typename Traits::char_type char_type; + + assert_bol_matcher(Traits const &tr) + : assert_line_base<Traits>(tr) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.bos()) + { + if(!state.flags_.match_bol_) + { + return false; + } + } + else + { + char_type ch = *boost::prior(state.cur_); + + // If the previous character is not a newline, we're not at the start of a line + if(!traits_cast<Traits>(state).isctype(ch, this->newline_)) + { + return false; + } + // There is no line-break between \r and \n + else if(ch == this->cr_ && !state.eos() && *state.cur_ == this->nl_) + { + return false; + } + } + + return next.match(state); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_bos_matcher.hpp b/boost/xpressive/detail/core/matcher/assert_bos_matcher.hpp new file mode 100644 index 0000000000..00b63b0280 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_bos_matcher.hpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_bos_matcher.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_MATCHER_ASSERT_BOS_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ASSERT_BOS_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // assert_bos_matcher + // match the beginning of the sequence (\A) + struct assert_bos_matcher + { + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) + + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + return state.bos() && next.match(state); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_eol_matcher.hpp b/boost/xpressive/detail/core/matcher/assert_eol_matcher.hpp new file mode 100644 index 0000000000..abceb952e0 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_eol_matcher.hpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_eol_matcher.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_MATCHER_ASSERT_EOL_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ASSERT_EOL_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/next_prior.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/matcher/assert_line_base.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // assert_eol_matcher + // + template<typename Traits> + struct assert_eol_matcher + : assert_line_base<Traits> + { + typedef typename Traits::char_type char_type; + + assert_eol_matcher(Traits const &tr) + : assert_line_base<Traits>(tr) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos()) + { + if(!state.flags_.match_eol_) + { + return false; + } + } + else + { + char_type ch = *state.cur_; + + // If the current character is not a newline, we're not at the end of a line + if(!traits_cast<Traits>(state).isctype(ch, this->newline_)) + { + return false; + } + // There is no line-break between \r and \n + else if(ch == this->nl_ && (!state.bos() || state.flags_.match_prev_avail_) && *boost::prior(state.cur_) == this->cr_) + { + return false; + } + } + + return next.match(state); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_eos_matcher.hpp b/boost/xpressive/detail/core/matcher/assert_eos_matcher.hpp new file mode 100644 index 0000000000..a0acbdd369 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_eos_matcher.hpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_eos_matcher.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_MATCHER_ASSERT_EOS_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ASSERT_EOS_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // assert_eos_matcher + // match the end of the sequence (\Z) + struct assert_eos_matcher + { + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) + + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + return state.eos() && next.match(state); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_line_base.hpp b/boost/xpressive/detail/core/matcher/assert_line_base.hpp new file mode 100644 index 0000000000..e10d90971a --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_line_base.hpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_line_base.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_MATCHER_DETAIL_ASSERT_LINE_BASE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_DETAIL_ASSERT_LINE_BASE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // assert_line_base + // + template<typename Traits> + struct assert_line_base + : quant_style_assertion + { + typedef typename Traits::char_type char_type; + typedef typename Traits::char_class_type char_class_type; + + protected: + assert_line_base(Traits const &tr) + : newline_(lookup_classname(tr, "newline")) + , nl_(tr.widen('\n')) + , cr_(tr.widen('\r')) + { + } + + char_class_type newline_; + char_type nl_, cr_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/assert_word_matcher.hpp b/boost/xpressive/detail/core/matcher/assert_word_matcher.hpp new file mode 100644 index 0000000000..444d88a5df --- /dev/null +++ b/boost/xpressive/detail/core/matcher/assert_word_matcher.hpp @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// assert_word_matcher.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_MATCHER_ASSERT_WORD_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ASSERT_WORD_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // word_boundary + // + template<typename IsBoundary> + struct word_boundary + { + template<typename BidiIter> + static bool eval(bool prevword, bool thisword, match_state<BidiIter> &state) + { + if((state.flags_.match_not_bow_ && state.bos()) || (state.flags_.match_not_eow_ && state.eos())) + { + return !IsBoundary::value; + } + + return IsBoundary::value == (prevword != thisword); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // word_begin + // + struct word_begin + { + template<typename BidiIter> + static bool eval(bool prevword, bool thisword, match_state<BidiIter> &state) + { + if(state.flags_.match_not_bow_ && state.bos()) + { + return false; + } + + return !prevword && thisword; + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // word_end + // + struct word_end + { + template<typename BidiIter> + static bool eval(bool prevword, bool thisword, match_state<BidiIter> &state) + { + if(state.flags_.match_not_eow_ && state.eos()) + { + return false; + } + + return prevword && !thisword; + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // assert_word_matcher + // + template<typename Cond, typename Traits> + struct assert_word_matcher + : quant_style_assertion + { + typedef typename Traits::char_type char_type; + typedef typename Traits::char_class_type char_class_type; + + assert_word_matcher(Traits const &tr) + : word_(lookup_classname(tr, "w")) + { + BOOST_ASSERT(0 != this->word_); + } + + assert_word_matcher(char_class_type word) + : word_(word) + {} + + bool is_word(Traits const &tr, char_type ch) const + { + detail::ignore_unused(tr); + return tr.isctype(tr.translate(ch), this->word_); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + BidiIter cur = state.cur_; + bool const thisword = !state.eos() && this->is_word(traits_cast<Traits>(state), *cur); + bool const prevword = (!state.bos() || state.flags_.match_prev_avail_) + && this->is_word(traits_cast<Traits>(state), *--cur); + + return Cond::eval(prevword, thisword, state) && next.match(state); + } + + char_class_type word() const + { + return this->word_; + } + + private: + char_class_type word_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/attr_begin_matcher.hpp b/boost/xpressive/detail/core/matcher/attr_begin_matcher.hpp new file mode 100644 index 0000000000..86d48a4d39 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/attr_begin_matcher.hpp @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// attr_begin_matcher.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_MATCHER_ATTR_BEGIN_MATCHER_HPP_EAN_06_09_2007 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ATTR_BEGIN_MATCHER_HPP_EAN_06_09_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // attr_begin_matcher + // + template<typename Nbr> + struct attr_begin_matcher + : quant_style<quant_none, 0, false> + { + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + void const *attr_slots[Nbr::value] = {}; + attr_context old_attr_context = state.attr_context_; + state.attr_context_.attr_slots_ = attr_slots; + state.attr_context_.prev_attr_context_ = &old_attr_context; + + if(next.match(state)) + { + return true; + } + + state.attr_context_ = old_attr_context; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/attr_end_matcher.hpp b/boost/xpressive/detail/core/matcher/attr_end_matcher.hpp new file mode 100644 index 0000000000..1ad23c28b9 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/attr_end_matcher.hpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// attr_end_matcher.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_MATCHER_ATTR_END_MATCHER_HPP_EAN_06_09_2007 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ATTR_END_MATCHER_HPP_EAN_06_09_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // attr_end_matcher + // + struct attr_end_matcher + : quant_style<quant_none, 0, false> + { + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + attr_context old_attr_context = state.attr_context_; + state.attr_context_ = *old_attr_context.prev_attr_context_; + + if(next.match(state)) + { + return true; + } + + state.attr_context_ = old_attr_context; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/attr_matcher.hpp b/boost/xpressive/detail/core/matcher/attr_matcher.hpp new file mode 100644 index 0000000000..7d8e67281a --- /dev/null +++ b/boost/xpressive/detail/core/matcher/attr_matcher.hpp @@ -0,0 +1,111 @@ +/////////////////////////////////////////////////////////////////////////////// +// attr_matcher.hpp +// +// Copyright 2008 Eric Niebler. +// Copyright 2008 David Jenkins. +// +// 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_MATCHER_ATTR_MATCHER_HPP_EAN_06_09_2007 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ATTR_MATCHER_HPP_EAN_06_09_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/symbols.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // char_translate + // + template<typename Traits, bool ICase> + struct char_translate + { + typedef typename Traits::char_type char_type; + Traits const &traits_; + + explicit char_translate(Traits const &tr) + : traits_(tr) + {} + + char_type operator ()(char_type ch1) const + { + return this->traits_.translate(ch1); + } + private: + char_translate &operator =(char_translate const &); + }; + + /////////////////////////////////////////////////////////////////////////////// + // char_translate + // + template<typename Traits> + struct char_translate<Traits, true> + { + typedef typename Traits::char_type char_type; + Traits const &traits_; + + explicit char_translate(Traits const &tr) + : traits_(tr) + {} + + char_type operator ()(char_type ch1) const + { + return this->traits_.translate_nocase(ch1); + } + private: + char_translate &operator =(char_translate const &); + }; + + /////////////////////////////////////////////////////////////////////////////// + // attr_matcher + // Note: the Matcher is a std::map + template<typename Matcher, typename Traits, typename ICase> + struct attr_matcher + : quant_style<quant_none, 0, false> + { + typedef typename Matcher::value_type::second_type const* result_type; + + attr_matcher(int slot, Matcher const &matcher, Traits const& tr) + : slot_(slot-1) + { + char_translate<Traits, ICase::value> trans(tr); + this->sym_.load(matcher, trans); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + BidiIter tmp = state.cur_; + char_translate<Traits, ICase::value> trans(traits_cast<Traits>(state)); + result_type const &result = this->sym_(state.cur_, state.end_, trans); + if(result) + { + void const *old_slot = state.attr_context_.attr_slots_[this->slot_]; + state.attr_context_.attr_slots_[this->slot_] = &*result; + if(next.match(state)) + { + return true; + } + state.attr_context_.attr_slots_[this->slot_] = old_slot; + } + state.cur_ = tmp; + return false; + } + + int slot_; + boost::xpressive::detail::symbols<Matcher> sym_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/charset_matcher.hpp b/boost/xpressive/detail/core/matcher/charset_matcher.hpp new file mode 100644 index 0000000000..66d1d298f2 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/charset_matcher.hpp @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// charset_matcher.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_MATCHER_CHARSET_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_CHARSET_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // charset_matcher + // + template<typename Traits, typename ICase, typename CharSet> + struct charset_matcher + : quant_style_fixed_width<1> + { + typedef typename Traits::char_type char_type; + typedef Traits traits_type; + typedef ICase icase_type; + + charset_matcher(CharSet const &charset = CharSet()) + : charset_(charset) + { + } + + void inverse() + { + this->charset_.inverse(); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos() || !this->charset_.test(*state.cur_, traits_cast<Traits>(state), icase_type())) + { + return false; + } + + ++state.cur_; + if(next.match(state)) + { + return true; + } + + --state.cur_; + return false; + } + + CharSet charset_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/end_matcher.hpp b/boost/xpressive/detail/core/matcher/end_matcher.hpp new file mode 100644 index 0000000000..2b10db4a18 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/end_matcher.hpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// end_matcher.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_MATCHER_END_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_END_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/sub_match_impl.hpp> +#include <boost/xpressive/detail/core/flow_control.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // end_matcher + // + struct end_matcher + : quant_style_assertion + { + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &) + { + BidiIter const tmp = state.cur_; + sub_match_impl<BidiIter> &s0 = state.sub_match(0); + BOOST_ASSERT(!s0.matched); + + // SPECIAL: if there is a match context on the context stack, then + // this pattern has been nested within another. pop that context and + // continue executing. + if(0 != state.context_.prev_context_) + { + if(!pop_context_match(state)) + { + return false; + } + + // record the end of sub-match zero + s0.first = s0.begin_; + s0.second = tmp; + s0.matched = true; + + return true; + } + else if((state.flags_.match_all_ && !state.eos()) || + (state.flags_.match_not_null_ && state.cur_ == s0.begin_)) + { + return false; + } + + // record the end of sub-match zero + s0.first = s0.begin_; + s0.second = tmp; + s0.matched = true; + + // Now execute any actions that have been queued + for(actionable const *actor = state.action_list_.next; 0 != actor; actor = actor->next) + { + actor->execute(state.action_args_); + } + + return true; + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // independent_end_matcher + // + struct independent_end_matcher + : quant_style_assertion + { + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &) const + { + // Now execute any actions that have been queued + for(actionable const *actor = state.action_list_.next; 0 != actor; actor = actor->next) + { + actor->execute(state.action_args_); + } + + return true; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/epsilon_matcher.hpp b/boost/xpressive/detail/core/matcher/epsilon_matcher.hpp new file mode 100644 index 0000000000..3452b3462d --- /dev/null +++ b/boost/xpressive/detail/core/matcher/epsilon_matcher.hpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// epsilon_matcher.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_MATCHER_EPSILON_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_EPSILON_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // epsilon_matcher + // + struct epsilon_matcher + { + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) + + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &state, Next const &next) + { + return next.match(state); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/keeper_matcher.hpp b/boost/xpressive/detail/core/matcher/keeper_matcher.hpp new file mode 100644 index 0000000000..d4b31e47e1 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/keeper_matcher.hpp @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////// +// keeper_matcher.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_MATCHER_KEEPER_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_KEEPER_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // keeper_matcher + // Xpr can be either a static_xpression, or a shared_matchable + template<typename Xpr> + struct keeper_matcher + : quant_style<quant_variable_width, unknown_width::value, Xpr::pure> + { + keeper_matcher(Xpr const &xpr, bool pure = Xpr::pure) + : xpr_(xpr) + , pure_(pure) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return Xpr::pure || this->pure_ + ? this->match_(state, next, mpl::true_()) + : this->match_(state, next, mpl::false_()); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const + { + BidiIter const tmp = state.cur_; + + // matching xpr is guaranteed to not produce side-effects, don't bother saving state + if(!this->xpr_.match(state)) + { + return false; + } + else if(next.match(state)) + { + return true; + } + + state.cur_ = tmp; + return false; + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const + { + BidiIter const tmp = state.cur_; + + // matching xpr could produce side-effects, save state + memento<BidiIter> mem = save_sub_matches(state); + + if(!this->xpr_.match(state)) + { + restore_action_queue(mem, state); + reclaim_sub_matches(mem, state, false); + return false; + } + restore_action_queue(mem, state); + if(next.match(state)) + { + reclaim_sub_matches(mem, state, true); + return true; + } + + restore_sub_matches(mem, state); + state.cur_ = tmp; + return false; + } + + Xpr xpr_; + bool pure_; // false if matching xpr_ could modify the sub-matches + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/literal_matcher.hpp b/boost/xpressive/detail/core/matcher/literal_matcher.hpp new file mode 100644 index 0000000000..ee862363a0 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/literal_matcher.hpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// literal_matcher.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_MATCHER_LITERAL_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LITERAL_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // literal_matcher + // + template<typename Traits, typename ICase, typename Not> + struct literal_matcher + : quant_style_fixed_width<1> + { + typedef typename Traits::char_type char_type; + typedef Not not_type; + typedef ICase icase_type; + char_type ch_; + + explicit literal_matcher(char_type ch) + : ch_(ch) + {} + + literal_matcher(char_type ch, Traits const &tr) + : ch_(detail::translate(ch, tr, icase_type())) + {} + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos() || Not::value == + (detail::translate(*state.cur_, traits_cast<Traits>(state), icase_type()) == this->ch_)) + { + return false; + } + + ++state.cur_; + if(next.match(state)) + { + return true; + } + + --state.cur_; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/logical_newline_matcher.hpp b/boost/xpressive/detail/core/matcher/logical_newline_matcher.hpp new file mode 100644 index 0000000000..be490f603c --- /dev/null +++ b/boost/xpressive/detail/core/matcher/logical_newline_matcher.hpp @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////// +// logical_newline_matcher.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_MATCHER_LOGICAL_NEWLINE_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOGICAL_NEWLINE_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + ////////////////////////////////////////////////////////////////////////// + // logical_newline_matcher + // + template<typename Traits> + struct logical_newline_matcher + : quant_style_variable_width + { + typedef typename Traits::char_type char_type; + typedef typename Traits::char_class_type char_class_type; + + logical_newline_matcher(Traits const &tr) + : newline_(lookup_classname(tr, "newline")) + , nl_(tr.widen('\n')) + , cr_(tr.widen('\r')) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos()) + { + return false; + } + + char_type ch = *state.cur_; + if(traits_cast<Traits>(state).isctype(ch, this->newline_)) + { + ++state.cur_; + if(this->cr_ == ch && !state.eos() && this->nl_ == *state.cur_) + { + ++state.cur_; + if(next.match(state)) + { + return true; + } + --state.cur_; + } + else if(next.match(state)) + { + return true; + } + + --state.cur_; + } + return false; + } + + char_class_type newline() const + { + return this->newline_; + } + + private: + char_class_type newline_; + char_type nl_, cr_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/lookahead_matcher.hpp b/boost/xpressive/detail/core/matcher/lookahead_matcher.hpp new file mode 100644 index 0000000000..06f25e45e2 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/lookahead_matcher.hpp @@ -0,0 +1,151 @@ +/////////////////////////////////////////////////////////////////////////////// +// lookahead_matcher.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_MATCHER_LOOKAHEAD_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKAHEAD_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/save_restore.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // lookahead_matcher + // Xpr can be either a static_xpression, or a shared_matchable + // + template<typename Xpr> + struct lookahead_matcher + : quant_style<quant_none, 0, Xpr::pure> + { + lookahead_matcher(Xpr const &xpr, bool no, bool pure = Xpr::pure) + : xpr_(xpr) + , not_(no) + , pure_(pure) + { + } + + void inverse() + { + this->not_ = !this->not_; + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return Xpr::pure || this->pure_ + ? this->match_(state, next, mpl::true_()) + : this->match_(state, next, mpl::false_()); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const + { + BidiIter const tmp = state.cur_; + + if(this->not_) + { + // negative look-ahead assertions do not trigger partial matches. + save_restore<bool> partial_match(state.found_partial_match_); + detail::ignore_unused(partial_match); + + if(this->xpr_.match(state)) + { + state.cur_ = tmp; + return false; + } + else if(next.match(state)) + { + return true; + } + } + else + { + if(!this->xpr_.match(state)) + { + return false; + } + state.cur_ = tmp; + if(next.match(state)) + { + return true; + } + } + + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const + { + BidiIter const tmp = state.cur_; + + // matching xpr could produce side-effects, save state + memento<BidiIter> mem = save_sub_matches(state); + + if(this->not_) + { + // negative look-ahead assertions do not trigger partial matches. + save_restore<bool> partial_match(state.found_partial_match_); + detail::ignore_unused(partial_match); + + if(this->xpr_.match(state)) + { + restore_action_queue(mem, state); + restore_sub_matches(mem, state); + state.cur_ = tmp; + return false; + } + restore_action_queue(mem, state); + if(next.match(state)) + { + reclaim_sub_matches(mem, state, true); + return true; + } + reclaim_sub_matches(mem, state, false); + } + else + { + if(!this->xpr_.match(state)) + { + restore_action_queue(mem, state); + reclaim_sub_matches(mem, state, false); + return false; + } + state.cur_ = tmp; + restore_action_queue(mem, state); + if(next.match(state)) + { + reclaim_sub_matches(mem, state, true); + return true; + } + restore_sub_matches(mem, state); + } + + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + + Xpr xpr_; + bool not_; + bool pure_; // false if matching xpr_ could modify the sub-matches + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/lookbehind_matcher.hpp b/boost/xpressive/detail/core/matcher/lookbehind_matcher.hpp new file mode 100644 index 0000000000..e75f5ed78f --- /dev/null +++ b/boost/xpressive/detail/core/matcher/lookbehind_matcher.hpp @@ -0,0 +1,168 @@ +/////////////////////////////////////////////////////////////////////////////// +// lookbehind_matcher.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_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/xpressive/regex_error.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> +#include <boost/xpressive/detail/utility/save_restore.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // lookbehind_matcher + // Xpr can be either a static_xpression or a shared_matchable + template<typename Xpr> + struct lookbehind_matcher + : quant_style<quant_none, 0, Xpr::pure> + { + lookbehind_matcher(Xpr const &xpr, std::size_t wid, bool no, bool pure = Xpr::pure) + : xpr_(xpr) + , not_(no) + , pure_(pure) + , width_(wid) + { + BOOST_XPR_ENSURE_(!is_unknown(this->width_), regex_constants::error_badlookbehind, + "Variable-width look-behind assertions are not supported"); + } + + void inverse() + { + this->not_ = !this->not_; + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return Xpr::pure || this->pure_ + ? this->match_(state, next, mpl::true_()) + : this->match_(state, next, mpl::false_()); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const + { + typedef typename iterator_difference<BidiIter>::type difference_type; + BidiIter const tmp = state.cur_; + if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) + { + state.cur_ = tmp; + return this->not_ ? next.match(state) : false; + } + + if(this->not_) + { + if(this->xpr_.match(state)) + { + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + state.cur_ = tmp; + if(next.match(state)) + { + return true; + } + } + else + { + if(!this->xpr_.match(state)) + { + state.cur_ = tmp; + return false; + } + BOOST_ASSERT(state.cur_ == tmp); + if(next.match(state)) + { + return true; + } + } + + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const + { + typedef typename iterator_difference<BidiIter>::type difference_type; + BidiIter const tmp = state.cur_; + if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) + { + state.cur_ = tmp; + return this->not_ ? next.match(state) : false; + } + + // matching xpr could produce side-effects, save state + memento<BidiIter> mem = save_sub_matches(state); + + if(this->not_) + { + // negative look-ahead assertions do not trigger partial matches. + save_restore<bool> partial_match(state.found_partial_match_); + detail::ignore_unused(partial_match); + + if(this->xpr_.match(state)) + { + restore_action_queue(mem, state); + restore_sub_matches(mem, state); + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + state.cur_ = tmp; + restore_action_queue(mem, state); + if(next.match(state)) + { + reclaim_sub_matches(mem, state, true); + return true; + } + reclaim_sub_matches(mem, state, false); + } + else + { + if(!this->xpr_.match(state)) + { + state.cur_ = tmp; + restore_action_queue(mem, state); + reclaim_sub_matches(mem, state, false); + return false; + } + BOOST_ASSERT(state.cur_ == tmp); + restore_action_queue(mem, state); + if(next.match(state)) + { + reclaim_sub_matches(mem, state, true); + return true; + } + restore_sub_matches(mem, state); + } + + BOOST_ASSERT(state.cur_ == tmp); + return false; + } + + Xpr xpr_; + bool not_; + bool pure_; // false if matching xpr_ could modify the sub-matches + std::size_t width_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/mark_begin_matcher.hpp b/boost/xpressive/detail/core/matcher/mark_begin_matcher.hpp new file mode 100644 index 0000000000..b73608a38f --- /dev/null +++ b/boost/xpressive/detail/core/matcher/mark_begin_matcher.hpp @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// mark_begin_matcher.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_MATCHER_MARK_BEGIN_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_MARK_BEGIN_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // mark_begin_matcher + // + struct mark_begin_matcher + : quant_style<quant_fixed_width, 0, false> + { + int mark_number_; // signed because it could be negative + + mark_begin_matcher(int mark_number) + : mark_number_(mark_number) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + BidiIter old_begin = br.begin_; + br.begin_ = state.cur_; + + if(next.match(state)) + { + return true; + } + + br.begin_ = old_begin; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/mark_end_matcher.hpp b/boost/xpressive/detail/core/matcher/mark_end_matcher.hpp new file mode 100644 index 0000000000..1316c1dfad --- /dev/null +++ b/boost/xpressive/detail/core/matcher/mark_end_matcher.hpp @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// mark_end_matcher.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_MATCHER_MARK_END_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_MARK_END_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // mark_end_matcher + // + struct mark_end_matcher + : quant_style<quant_none, 0, false> + { + int mark_number_; + + mark_end_matcher(int mark_number) + : mark_number_(mark_number) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + BidiIter old_first = br.first; + BidiIter old_second = br.second; + bool old_matched = br.matched; + + br.first = br.begin_; + br.second = state.cur_; + br.matched = true; + + if(next.match(state)) + { + return true; + } + + br.first = old_first; + br.second = old_second; + br.matched = old_matched; + + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/mark_matcher.hpp b/boost/xpressive/detail/core/matcher/mark_matcher.hpp new file mode 100644 index 0000000000..a4696e1938 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/mark_matcher.hpp @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////// +// mark_matcher.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_MATCHER_MARK_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_MARK_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + // TODO: the mark matcher is acually a fixed-width matcher, but the width is + // not known until pattern match time. + + /////////////////////////////////////////////////////////////////////////////// + // mark_matcher + // + template<typename Traits, typename ICase> + struct mark_matcher + : quant_style_variable_width + { + typedef ICase icase_type; + int mark_number_; + + mark_matcher(int mark_number, Traits const &) + : mark_number_(mark_number) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + BOOST_ASSERT(this->mark_number_ < static_cast<int>(state.mark_count_)); + sub_match_impl<BidiIter> const &br = state.sub_match(this->mark_number_); + + if(!br.matched) + { + return false; + } + + BidiIter const tmp = state.cur_; + for(BidiIter begin = br.first, end = br.second; begin != end; ++begin, ++state.cur_) + { + if(state.eos() + || detail::translate(*state.cur_, traits_cast<Traits>(state), icase_type()) + != detail::translate(*begin, traits_cast<Traits>(state), icase_type())) + { + state.cur_ = tmp; + return false; + } + } + + if(next.match(state)) + { + return true; + } + + state.cur_ = tmp; + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/optional_matcher.hpp b/boost/xpressive/detail/core/matcher/optional_matcher.hpp new file mode 100644 index 0000000000..ab4ac59840 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/optional_matcher.hpp @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// optional_matcher.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_MATCHER_OPTIONAL_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_OPTIONAL_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // optional_matcher + template<typename Xpr, typename Greedy> + struct optional_matcher + : quant_style<quant_variable_width, unknown_width::value, Xpr::pure> + { + Xpr xpr_; + + explicit optional_matcher(Xpr const &xpr) + : xpr_(xpr) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return this->match_(state, next, Greedy()); + } + + private: + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const // Greedy + { + return this->xpr_.BOOST_NESTED_TEMPLATE push_match<Next>(state) + || next.match(state); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const // Non-greedy + { + return next.match(state) + || this->xpr_.BOOST_NESTED_TEMPLATE push_match<Next>(state); + } + + optional_matcher &operator =(optional_matcher const &); + }; + + /////////////////////////////////////////////////////////////////////////////// + // optional_mark_matcher + template<typename BidiIter, typename Next> + inline bool match_next(match_state<BidiIter> &state, Next const &next, int mark_number) + { + sub_match_impl<BidiIter> &br = state.sub_match(mark_number); + + bool old_matched = br.matched; + br.matched = false; + + if(next.match(state)) + { + return true; + } + + br.matched = old_matched; + return false; + } + + /////////////////////////////////////////////////////////////////////////////// + // optional_mark_matcher + template<typename Xpr, typename Greedy> + struct optional_mark_matcher + : quant_style<quant_variable_width, unknown_width::value, Xpr::pure> + { + Xpr xpr_; + int mark_number_; + + explicit optional_mark_matcher(Xpr const &xpr, int mark_number) + : xpr_(xpr) + , mark_number_(mark_number) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + return this->match_(state, next, Greedy()); + } + + private: + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const // Greedy + { + return this->xpr_.BOOST_NESTED_TEMPLATE push_match<Next>(state) + || match_next(state, next, this->mark_number_); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const // Non-greedy + { + return match_next(state, next, this->mark_number_) + || this->xpr_.BOOST_NESTED_TEMPLATE push_match<Next>(state); + } + + optional_mark_matcher &operator =(optional_mark_matcher const &); + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/posix_charset_matcher.hpp b/boost/xpressive/detail/core/matcher/posix_charset_matcher.hpp new file mode 100644 index 0000000000..19e87bf42f --- /dev/null +++ b/boost/xpressive/detail/core/matcher/posix_charset_matcher.hpp @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////// +// posix_charset_matcher.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_MATCHER_POSIX_CHARSET_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_POSIX_CHARSET_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // posix_charset_matcher + // + template<typename Traits> + struct posix_charset_matcher + : quant_style_fixed_width<1> + { + typedef Traits traits_type; + typedef typename Traits::char_class_type char_class_type; + + posix_charset_matcher(char_class_type m, bool no) + : not_(no) + , mask_(m) + { + BOOST_ASSERT(0 != this->mask_); + } + + void inverse() + { + this->not_ = !this->not_; + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos() || this->not_ == traits_cast<Traits>(state).isctype( + *state.cur_, this->mask_)) + { + return false; + } + + ++state.cur_; + if(next.match(state)) + { + return true; + } + + --state.cur_; + return false; + } + + bool not_; + char_class_type mask_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/predicate_matcher.hpp b/boost/xpressive/detail/core/matcher/predicate_matcher.hpp new file mode 100644 index 0000000000..eced1c7643 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/predicate_matcher.hpp @@ -0,0 +1,174 @@ +/////////////////////////////////////////////////////////////////////////////// +// predicate_matcher.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_MATCHER_PREDICATE_MATCHER_HPP_EAN_03_22_2007 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_PREDICATE_MATCHER_HPP_EAN_03_22_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/not.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/matcher/action_matcher.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/proto/core.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // predicate_context + // + template<typename BidiIter> + struct predicate_context + { + explicit predicate_context(int sub, sub_match_impl<BidiIter> const *sub_matches, action_args_type *action_args) + : sub_(sub) + , sub_matches_(sub_matches) + , action_args_(action_args) + {} + + action_args_type const &args() const + { + return *this->action_args_; + } + + // eval_terminal + template<typename Expr, typename Arg> + struct eval_terminal + : proto::default_eval<Expr, predicate_context const> + {}; + + template<typename Expr, typename Arg> + struct eval_terminal<Expr, reference_wrapper<Arg> > + { + typedef Arg &result_type; + result_type operator()(Expr &expr, predicate_context const &) const + { + return proto::value(expr).get(); + } + }; + + template<typename Expr> + struct eval_terminal<Expr, any_matcher> + { + typedef sub_match<BidiIter> const &result_type; + result_type operator()(Expr &, predicate_context const &ctx) const + { + return ctx.sub_matches_[ctx.sub_]; + } + }; + + template<typename Expr> + struct eval_terminal<Expr, mark_placeholder> + { + typedef sub_match<BidiIter> const &result_type; + result_type operator()(Expr &expr, predicate_context const &ctx) const + { + return ctx.sub_matches_[proto::value(expr).mark_number_]; + } + }; + + template<typename Expr, typename Type, typename Int> + struct eval_terminal<Expr, action_arg<Type, Int> > + { + typedef typename action_arg<Type, Int>::reference result_type; + result_type operator()(Expr &expr, predicate_context const &ctx) const + { + action_args_type::const_iterator where_ = ctx.args().find(&typeid(proto::value(expr))); + if(where_ == ctx.args().end()) + { + BOOST_THROW_EXCEPTION( + regex_error( + regex_constants::error_badarg + , "An argument to an action was unspecified" + ) + ); + } + return proto::value(expr).cast(where_->second); + } + }; + + // eval + template<typename Expr, typename Tag = typename Expr::proto_tag> + struct eval + : proto::default_eval<Expr, predicate_context const> + {}; + + template<typename Expr> + struct eval<Expr, proto::tag::terminal> + : eval_terminal<Expr, typename proto::result_of::value<Expr>::type> + {}; + + #if BOOST_VERSION >= 103500 + template<typename Expr> + struct eval<Expr, proto::tag::mem_ptr> + : mem_ptr_eval<Expr, predicate_context const> + {}; + #endif + + int sub_; + sub_match_impl<BidiIter> const *sub_matches_; + action_args_type *action_args_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // AssertionFunctor + // + struct AssertionFunctor + : proto::function< + proto::terminal<check_tag> + , proto::terminal<proto::_> + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // predicate_matcher + // + template<typename Predicate> + struct predicate_matcher + : quant_style_assertion + { + int sub_; + Predicate predicate_; + + predicate_matcher(Predicate const &pred, int sub) + : sub_(sub) + , predicate_(pred) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + // Predicate is check(assertion), where assertion can be + // a lambda or a function object. + return this->match_(state, next, proto::matches<Predicate, AssertionFunctor>()); + } + + private: + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const + { + sub_match<BidiIter> const &sub = state.sub_match(this->sub_); + return proto::value(proto::child_c<1>(this->predicate_))(sub) && next.match(state); + } + + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const + { + predicate_context<BidiIter> ctx(this->sub_, state.sub_matches_, state.action_args_); + return proto::eval(proto::child_c<1>(this->predicate_), ctx) && next.match(state); + } + }; + +}}} + +#endif // BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_PREDICATE_MATCHER_HPP_EAN_03_22_2007 diff --git a/boost/xpressive/detail/core/matcher/range_matcher.hpp b/boost/xpressive/detail/core/matcher/range_matcher.hpp new file mode 100644 index 0000000000..2f2c6974d8 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/range_matcher.hpp @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +// range_matcher.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_MATCHER_RANGE_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_RANGE_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // range_matcher + // + template<typename Traits, typename ICase> + struct range_matcher + : quant_style_fixed_width<1> + { + typedef typename Traits::char_type char_type; + typedef ICase icase_type; + char_type ch_min_; + char_type ch_max_; + bool not_; + + range_matcher(char_type ch_min, char_type ch_max, bool no, Traits const &) + : ch_min_(ch_min) + , ch_max_(ch_max) + , not_(no) + { + } + + void inverse() + { + this->not_ = !this->not_; + } + + bool in_range(Traits const &tr, char_type ch, mpl::false_) const // case-sensitive + { + return tr.in_range(this->ch_min_, this->ch_max_, ch); + } + + bool in_range(Traits const &tr, char_type ch, mpl::true_) const // case-insensitive + { + return tr.in_range_nocase(this->ch_min_, this->ch_max_, ch); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos() || this->not_ == + this->in_range(traits_cast<Traits>(state), *state.cur_, icase_type())) + { + return false; + } + + ++state.cur_; + if(next.match(state)) + { + return true; + } + + --state.cur_; + return false; + } + }; + +}}} + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/core/matcher/regex_byref_matcher.hpp b/boost/xpressive/detail/core/matcher/regex_byref_matcher.hpp new file mode 100644 index 0000000000..f92820424e --- /dev/null +++ b/boost/xpressive/detail/core/matcher/regex_byref_matcher.hpp @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// regex_byref_matcher.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_MATCHER_REGEX_BYREF_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_REGEX_BYREF_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/xpressive/regex_error.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/core/adaptor.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // regex_byref_matcher + // + template<typename BidiIter> + struct regex_byref_matcher + : quant_style<quant_variable_width, unknown_width::value, false> + { + // avoid cyclic references by holding a weak_ptr to the + // regex_impl struct + weak_ptr<regex_impl<BidiIter> > wimpl_; + + // the basic_regex object holds a ref-count to this regex_impl, so + // we don't have to worry about it going away. + regex_impl<BidiIter> const *pimpl_; + + regex_byref_matcher(shared_ptr<regex_impl<BidiIter> > const &impl) + : wimpl_(impl) + , pimpl_(impl.get()) + { + BOOST_ASSERT(this->pimpl_); + } + + template<typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + BOOST_ASSERT(this->pimpl_ == this->wimpl_.lock().get()); + BOOST_XPR_ENSURE_(this->pimpl_->xpr_, regex_constants::error_badref, "bad regex reference"); + + return push_context_match(*this->pimpl_, state, this->wrap_(next, is_static_xpression<Next>())); + } + + private: + template<typename Next> + static xpression_adaptor<reference_wrapper<Next const>, matchable<BidiIter> > wrap_(Next const &next, mpl::true_) + { + // wrap the static xpression in a matchable interface + return xpression_adaptor<reference_wrapper<Next const>, matchable<BidiIter> >(boost::cref(next)); + } + + template<typename Next> + static Next const &wrap_(Next const &next, mpl::false_) + { + return next; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/regex_matcher.hpp b/boost/xpressive/detail/core/matcher/regex_matcher.hpp new file mode 100644 index 0000000000..e7eee7d3ea --- /dev/null +++ b/boost/xpressive/detail/core/matcher/regex_matcher.hpp @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// regex_matcher.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_MATCHER_REGEX_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_REGEX_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/xpressive/regex_error.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/adaptor.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // regex_matcher + // + template<typename BidiIter> + struct regex_matcher + : quant_style<quant_variable_width, unknown_width::value, false> + { + regex_impl<BidiIter> impl_; + + regex_matcher(shared_ptr<regex_impl<BidiIter> > const &impl) + : impl_() + { + this->impl_.xpr_ = impl->xpr_; + this->impl_.traits_ = impl->traits_; + this->impl_.mark_count_ = impl->mark_count_; + this->impl_.hidden_mark_count_ = impl->hidden_mark_count_; + + BOOST_XPR_ENSURE_(this->impl_.xpr_, regex_constants::error_badref, "bad regex reference"); + } + + template<typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + // regex_matcher is used for embeding a dynamic regex in a static regex. As such, + // Next will always point to a static regex. + BOOST_MPL_ASSERT((is_static_xpression<Next>)); + + // wrap the static xpression in a matchable interface + xpression_adaptor<reference_wrapper<Next const>, matchable<BidiIter> > adaptor(boost::cref(next)); + return push_context_match(this->impl_, state, adaptor); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/repeat_begin_matcher.hpp b/boost/xpressive/detail/core/matcher/repeat_begin_matcher.hpp new file mode 100644 index 0000000000..bcc59ee70f --- /dev/null +++ b/boost/xpressive/detail/core/matcher/repeat_begin_matcher.hpp @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////// +// repeat_end_matcher.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_MATCHER_REPEAT_BEGIN_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_REPEAT_BEGIN_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + // + // Note: here is the variable-width xpression quantifier. It always + // matches at least once, so if the min is 0, it is the responsibility + // of the parser to make it alternate with an epsilon matcher. + // + + /////////////////////////////////////////////////////////////////////////////// + // repeat_begin_matcher + // + struct repeat_begin_matcher + : quant_style<quant_variable_width, unknown_width::value, false> + { + int mark_number_; + + repeat_begin_matcher(int mark_number) + : mark_number_(mark_number) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + unsigned int old_repeat_count = br.repeat_count_; + bool old_zero_width = br.zero_width_; + + br.repeat_count_ = 1; + br.zero_width_ = false; + + // "push" next onto the stack, so it can be "popped" in + // repeat_end_matcher and used to loop back. + if(next.BOOST_NESTED_TEMPLATE push_match<Next>(state)) + { + return true; + } + + br.repeat_count_ = old_repeat_count; + br.zero_width_ = old_zero_width; + + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/repeat_end_matcher.hpp b/boost/xpressive/detail/core/matcher/repeat_end_matcher.hpp new file mode 100644 index 0000000000..c2dc4495b5 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/repeat_end_matcher.hpp @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// repeat_end_matcher.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_MATCHER_REPEAT_END_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_REPEAT_END_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // repeat_end_matcher + // + template<typename Greedy> + struct repeat_end_matcher + : quant_style<quant_none, 0, false> + { + typedef Greedy greedy_type; + int mark_number_; + unsigned int min_, max_; + mutable void const *back_; + + repeat_end_matcher(int mark_nbr, unsigned int min, unsigned int max) + : mark_number_(mark_nbr) + , min_(min) + , max_(max) + , back_(0) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + // prevent repeated zero-width sub-matches from causing infinite recursion + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + if(br.zero_width_ && br.begin_ == state.cur_) + { + return next.skip_match(state); + } + + bool old_zero_width = br.zero_width_; + br.zero_width_ = (br.begin_ == state.cur_); + + if(this->match_(state, next, greedy_type())) + { + return true; + } + + br.zero_width_ = old_zero_width; + return false; + } + + // greedy, variable-width quantifier + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const + { + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + if(this->max_ > br.repeat_count_) + { + ++br.repeat_count_; + // loop back to the expression "pushed" in repeat_begin_matcher::match + if(next.top_match(state, this->back_)) + { + return true; + } + else if(--br.repeat_count_ < this->min_) + { + return false; + } + } + + // looping finished, continue matching the rest of the pattern + return next.skip_match(state); + } + + // non-greedy, variable-width quantifier + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const + { + sub_match_impl<BidiIter> &br = state.sub_match(this->mark_number_); + + if(this->min_ <= br.repeat_count_) + { + if(next.skip_match(state)) + { + return true; + } + } + + if(this->max_ > br.repeat_count_) + { + ++br.repeat_count_; + if(next.top_match(state, this->back_)) + { + return true; + } + --br.repeat_count_; + } + + return false; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/set_matcher.hpp b/boost/xpressive/detail/core/matcher/set_matcher.hpp new file mode 100644 index 0000000000..124a545fe7 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/set_matcher.hpp @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////// +// set.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_SET_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_SET_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4127) // conditional expression constant +# pragma warning(disable : 4100) // unreferenced formal parameter +# pragma warning(disable : 4351) // vc8 new behavior: elements of array 'foo' will be default initialized +#endif + +#include <algorithm> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/same_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// set_matcher +// +template<typename Traits, typename Size> +struct set_matcher + : quant_style_fixed_width<1> +{ + typedef typename Traits::char_type char_type; + char_type set_[ Size::value ]; + bool not_; + bool icase_; + + set_matcher() + : set_() + , not_(false) + , icase_(false) + { + } + + void inverse() + { + this->not_ = !this->not_; + } + + void nocase(Traits const &tr) + { + this->icase_ = true; + + for(int i = 0; i < Size::value; ++i) + { + this->set_[i] = tr.translate_nocase(this->set_[i]); + } + } + + bool in_set(Traits const &tr, char_type ch) const + { + char_type const *begin = &this->set_[0], *end = begin + Size::value; + ch = this->icase_ ? tr.translate_nocase(ch) : tr.translate(ch); + return end != std::find(begin, end, ch); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + if(state.eos() || this->not_ == this->in_set(traits_cast<Traits>(state), *state.cur_)) + { + return false; + } + + if(++state.cur_, next.match(state)) + { + return true; + } + + return --state.cur_, false; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// set_initializer +struct set_initializer +{ +}; + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/matcher/simple_repeat_matcher.hpp b/boost/xpressive/detail/core/matcher/simple_repeat_matcher.hpp new file mode 100644 index 0000000000..26610f2868 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/simple_repeat_matcher.hpp @@ -0,0 +1,234 @@ +/////////////////////////////////////////////////////////////////////////////// +// simple_repeat_matcher.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_MATCHER_SIMPLE_REPEAT_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_SIMPLE_REPEAT_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/next_prior.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/static/type_traits.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // simple_repeat_traits + // + struct greedy_slow_tag {}; + struct greedy_fast_tag {}; + struct non_greedy_tag {}; + + typedef static_xpression<any_matcher, true_xpression> any_sxpr; + typedef matcher_wrapper<any_matcher> any_dxpr; + + template<typename Xpr, typename Greedy, typename Random> + struct simple_repeat_traits + { + typedef typename mpl::if_c<Greedy::value, greedy_slow_tag, non_greedy_tag>::type tag_type; + }; + + template<> + struct simple_repeat_traits<any_sxpr, mpl::true_, mpl::true_> + { + typedef greedy_fast_tag tag_type; + }; + + template<> + struct simple_repeat_traits<any_dxpr, mpl::true_, mpl::true_> + { + typedef greedy_fast_tag tag_type; + }; + + /////////////////////////////////////////////////////////////////////////////// + // simple_repeat_matcher + // + template<typename Xpr, typename Greedy> + struct simple_repeat_matcher + : quant_style_variable_width + { + typedef Xpr xpr_type; + typedef Greedy greedy_type; + + Xpr xpr_; + unsigned int min_, max_; + std::size_t width_; + mutable bool leading_; + + simple_repeat_matcher(Xpr const &xpr, unsigned int min, unsigned int max, std::size_t width) + : xpr_(xpr) + , min_(min) + , max_(max) + , width_(width) + , leading_(false) + { + // it is the job of the parser to make sure this never happens + BOOST_ASSERT(min <= max); + BOOST_ASSERT(0 != max); + BOOST_ASSERT(0 != width && unknown_width() != width); + BOOST_ASSERT(Xpr::width == unknown_width() || Xpr::width == width); + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + typedef mpl::bool_<is_random<BidiIter>::value> is_rand; + typedef typename simple_repeat_traits<Xpr, greedy_type, is_rand>::tag_type tag_type; + return this->match_(state, next, tag_type()); + } + + // greedy, fixed-width quantifier + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, greedy_slow_tag) const + { + int const diff = -static_cast<int>(Xpr::width == unknown_width::value ? this->width_ : Xpr::width); + unsigned int matches = 0; + BidiIter const tmp = state.cur_; + + // greedily match as much as we can + while(matches < this->max_ && this->xpr_.match(state)) + { + ++matches; + } + + // If this repeater is at the front of the pattern, note + // how much of the input we consumed so that a repeated search + // doesn't have to cover the same ground again. + if(this->leading_) + { + state.next_search_ = (matches && matches < this->max_) + ? state.cur_ + : (tmp == state.end_) ? tmp : boost::next(tmp); + } + + if(this->min_ > matches) + { + state.cur_ = tmp; + return false; + } + + // try matching the rest of the pattern, and back off if necessary + for(; ; --matches, std::advance(state.cur_, diff)) + { + if(next.match(state)) + { + return true; + } + else if(this->min_ == matches) + { + state.cur_ = tmp; + return false; + } + } + } + + // non-greedy fixed-width quantification + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, non_greedy_tag) const + { + BOOST_ASSERT(!this->leading_); + BidiIter const tmp = state.cur_; + unsigned int matches = 0; + + for(; matches < this->min_; ++matches) + { + if(!this->xpr_.match(state)) + { + state.cur_ = tmp; + return false; + } + } + + do + { + if(next.match(state)) + { + return true; + } + } + while(matches++ < this->max_ && this->xpr_.match(state)); + + state.cur_ = tmp; + return false; + } + + // when greedily matching any character, skip to the end instead of iterating there. + template<typename BidiIter, typename Next> + bool match_(match_state<BidiIter> &state, Next const &next, greedy_fast_tag) const + { + BidiIter const tmp = state.cur_; + std::size_t const diff_to_end = static_cast<std::size_t>(state.end_ - tmp); + + // is there enough room? + if(this->min_ > diff_to_end) + { + if(this->leading_) + { + state.next_search_ = (tmp == state.end_) ? tmp : boost::next(tmp); + } + return false; + } + + BidiIter const min_iter = tmp + this->min_; + state.cur_ += (std::min)((std::size_t)this->max_, diff_to_end); + + if(this->leading_) + { + state.next_search_ = (diff_to_end && diff_to_end < this->max_) + ? state.cur_ + : (tmp == state.end_) ? tmp : boost::next(tmp); + } + + for(;; --state.cur_) + { + if(next.match(state)) + { + return true; + } + else if(min_iter == state.cur_) + { + state.cur_ = tmp; + return false; + } + } + } + + detail::width get_width() const + { + if(this->min_ != this->max_) + { + return unknown_width::value; + } + return this->min_ * this->width_; + } + + private: + simple_repeat_matcher &operator =(simple_repeat_matcher const &); + }; + + // BUGBUG can all non-greedy quantification be done with the fixed width quantifier? + + // BUGBUG matchers are chained together using static_xpression so that matchers to + // the left can invoke matchers to the right. This is so that if the left matcher + // succeeds but the right matcher fails, the left matcher is given the opportunity + // to try something else. This is how backtracking works. However, if the left matcher + // can succeed only one way (as with any_matcher, for example), it does not need + // backtracking. In this case, leaving its stack frame active is a waste of stack + // space. Can something be done? + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/string_matcher.hpp b/boost/xpressive/detail/core/matcher/string_matcher.hpp new file mode 100644 index 0000000000..02b538c249 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/string_matcher.hpp @@ -0,0 +1,90 @@ +/////////////////////////////////////////////////////////////////////////////// +// string_matcher.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_MATCHER_STRING_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_STRING_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // string_matcher + // + template<typename Traits, typename ICase> + struct string_matcher + : quant_style_fixed_unknown_width + { + typedef typename Traits::char_type char_type; + typedef typename Traits::string_type string_type; + typedef ICase icase_type; + string_type str_; + char_type const *end_; + + string_matcher(string_type const &str, Traits const &tr) + : str_(str) + , end_() + { + typename range_iterator<string_type>::type cur = boost::begin(this->str_); + typename range_iterator<string_type>::type end = boost::end(this->str_); + for(; cur != end; ++cur) + { + *cur = detail::translate(*cur, tr, icase_type()); + } + this->end_ = detail::data_end(str_); + } + + string_matcher(string_matcher<Traits, ICase> const &that) + : str_(that.str_) + , end_(detail::data_end(str_)) + { + } + + template<typename BidiIter, typename Next> + bool match(match_state<BidiIter> &state, Next const &next) const + { + BidiIter const tmp = state.cur_; + char_type const *begin = detail::data_begin(this->str_); + for(; begin != this->end_; ++begin, ++state.cur_) + { + if(state.eos() || + (detail::translate(*state.cur_, traits_cast<Traits>(state), icase_type()) != *begin)) + { + state.cur_ = tmp; + return false; + } + } + + if(next.match(state)) + { + return true; + } + + state.cur_ = tmp; + return false; + } + + detail::width get_width() const + { + return boost::size(this->str_); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matcher/true_matcher.hpp b/boost/xpressive/detail/core/matcher/true_matcher.hpp new file mode 100644 index 0000000000..df45e47d21 --- /dev/null +++ b/boost/xpressive/detail/core/matcher/true_matcher.hpp @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// true_matcher.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_MATCHER_TRUE_MATCHER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_TRUE_MATCHER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/state.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // true_matcher + // + struct true_matcher + : quant_style_assertion + { + template<typename BidiIter, typename Next> + static bool match(match_state<BidiIter> &, Next const &) + { + return true; + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/core/matchers.hpp b/boost/xpressive/detail/core/matchers.hpp new file mode 100644 index 0000000000..8363ce0c1d --- /dev/null +++ b/boost/xpressive/detail/core/matchers.hpp @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// matchers.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_MATCHERS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHERS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +//#include <boost/xpressive/detail/core/matcher/action_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/alternate_end_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/alternate_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/any_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/assert_bol_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/assert_bos_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/assert_eol_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/assert_eos_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/assert_word_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/attr_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/charset_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/end_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/epsilon_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/keeper_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/literal_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/logical_newline_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/lookahead_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/lookbehind_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/mark_begin_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/mark_end_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/mark_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/optional_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/posix_charset_matcher.hpp> +//#include <boost/xpressive/detail/core/matcher/predicate_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/range_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/regex_byref_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/regex_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/repeat_begin_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/repeat_end_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/set_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/simple_repeat_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/string_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/true_matcher.hpp> + +#endif diff --git a/boost/xpressive/detail/core/optimize.hpp b/boost/xpressive/detail/core/optimize.hpp new file mode 100644 index 0000000000..f9d9ebebdc --- /dev/null +++ b/boost/xpressive/detail/core/optimize.hpp @@ -0,0 +1,116 @@ +/////////////////////////////////////////////////////////////////////////////// +// optimize.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_OPTIMIZE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_OPTIMIZE_HPP_EAN_10_04_2005 + +#include <string> +#include <utility> +#include <boost/mpl/bool.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/xpressive/detail/core/finder.hpp> +#include <boost/xpressive/detail/core/linker.hpp> +#include <boost/xpressive/detail/core/peeker.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// optimize_regex +// +template<typename BidiIter, typename Traits> +intrusive_ptr<finder<BidiIter> > optimize_regex +( + xpression_peeker<typename iterator_value<BidiIter>::type> const &peeker + , Traits const &tr + , mpl::false_ +) +{ + if(peeker.line_start()) + { + return intrusive_ptr<finder<BidiIter> > + ( + new line_start_finder<BidiIter, Traits>(tr) + ); + } + else if(peeker.leading_simple_repeat()) + { + return intrusive_ptr<finder<BidiIter> > + ( + new leading_simple_repeat_finder<BidiIter>() + ); + } + else if(256 != peeker.bitset().count()) + { + return intrusive_ptr<finder<BidiIter> > + ( + new hash_peek_finder<BidiIter, Traits>(peeker.bitset()) + ); + } + + return intrusive_ptr<finder<BidiIter> >(); +} + +/////////////////////////////////////////////////////////////////////////////// +// optimize_regex +// +template<typename BidiIter, typename Traits> +intrusive_ptr<finder<BidiIter> > optimize_regex +( + xpression_peeker<typename iterator_value<BidiIter>::type> const &peeker + , Traits const &tr + , mpl::true_ +) +{ + typedef typename iterator_value<BidiIter>::type char_type; + + // if we have a leading string literal, initialize a boyer-moore struct with it + peeker_string<char_type> const &str = peeker.get_string(); + if(str.begin_ != str.end_) + { + BOOST_ASSERT(1 == peeker.bitset().count()); + return intrusive_ptr<finder<BidiIter> > + ( + new boyer_moore_finder<BidiIter, Traits>(str.begin_, str.end_, tr, str.icase_) + ); + } + + return optimize_regex<BidiIter>(peeker, tr, mpl::false_()); +} + +/////////////////////////////////////////////////////////////////////////////// +// common_compile +// +template<typename BidiIter, typename Traits> +void common_compile +( + intrusive_ptr<matchable_ex<BidiIter> const> const ®ex + , regex_impl<BidiIter> &impl + , Traits const &tr +) +{ + typedef typename iterator_value<BidiIter>::type char_type; + + // "link" the regex + xpression_linker<char_type> linker(tr); + regex->link(linker); + + // "peek" into the compiled regex to see if there are optimization opportunities + hash_peek_bitset<char_type> bset; + xpression_peeker<char_type> peeker(bset, tr, linker.has_backrefs()); + regex->peek(peeker); + + // optimization: get the peek chars OR the boyer-moore search string + impl.finder_ = optimize_regex<BidiIter>(peeker, tr, is_random<BidiIter>()); + impl.xpr_ = regex; +} + +}}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/detail/core/peeker.hpp b/boost/xpressive/detail/core/peeker.hpp new file mode 100644 index 0000000000..45183fc49c --- /dev/null +++ b/boost/xpressive/detail/core/peeker.hpp @@ -0,0 +1,284 @@ +/////////////////////////////////////////////////////////////////////////////// +// peeker.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_PEEKER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_PEEKER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <typeinfo> +#include <boost/assert.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/mpl/size_t.hpp> +#include <boost/mpl/equal_to.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/matchers.hpp> +#include <boost/xpressive/detail/utility/hash_peek_bitset.hpp> +#include <boost/xpressive/detail/utility/never_true.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// peeker_string +// +template<typename Char> +struct peeker_string +{ + Char const *begin_; + Char const *end_; + bool icase_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// char_sink +// +template<typename Traits, bool ICase> +struct char_sink +{ + typedef typename Traits::char_type char_type; + + char_sink(hash_peek_bitset<char_type> &bset, Traits const &tr) + : bset_(bset) + , traits_(tr) + {} + + void operator()(char_type ch) const + { + this->bset_.set_char(ch, ICase, this->traits_); + } + + hash_peek_bitset<char_type> &bset_; + Traits const &traits_; +private: + char_sink &operator =(char_sink const &); +}; + +/////////////////////////////////////////////////////////////////////////////// +// xpression_peeker +// +template<typename Char> +struct xpression_peeker +{ + template<typename Traits> + xpression_peeker(hash_peek_bitset<Char> &bset, Traits const &tr, bool has_backrefs = false) + : bset_(bset) + , str_() + , line_start_(false) + , traits_(0) + , traits_type_(0) + , leading_simple_repeat_(0) + , has_backrefs_(has_backrefs) + { + this->set_traits(tr); + } + + /////////////////////////////////////////////////////////////////////////////// + // accessors + peeker_string<Char> const &get_string() const + { + return this->str_; + } + + bool line_start() const + { + return this->line_start_; + } + + bool leading_simple_repeat() const + { + return 0 < this->leading_simple_repeat_; + } + + hash_peek_bitset<Char> const &bitset() const + { + return this->bset_; + } + + /////////////////////////////////////////////////////////////////////////////// + // modifiers + void fail() + { + this->bset_.set_all(); + } + + template<typename Matcher> + mpl::false_ accept(Matcher const &) + { + this->fail(); + return mpl::false_(); + } + + mpl::true_ accept(mark_begin_matcher const &) + { + if(this->has_backrefs_) + { + --this->leading_simple_repeat_; + } + return mpl::true_(); + } + + mpl::true_ accept(repeat_begin_matcher const &) + { + --this->leading_simple_repeat_; + return mpl::true_(); + } + + template<typename Traits> + mpl::true_ accept(assert_bol_matcher<Traits> const &) + { + this->line_start_ = true; + return mpl::true_(); + } + + template<typename Traits, typename ICase> + mpl::false_ accept(literal_matcher<Traits, ICase, mpl::false_> const &xpr) + { + this->bset_.set_char(xpr.ch_, ICase(), this->get_traits_<Traits>()); + return mpl::false_(); + } + + template<typename Traits, typename ICase> + mpl::false_ accept(string_matcher<Traits, ICase> const &xpr) + { + this->bset_.set_char(xpr.str_[0], ICase(), this->get_traits_<Traits>()); + this->str_.begin_ = detail::data_begin(xpr.str_); + this->str_.end_ = detail::data_end(xpr.str_); + this->str_.icase_ = ICase::value; + return mpl::false_(); + } + + template<typename Alternates, typename Traits> + mpl::false_ accept(alternate_matcher<Alternates, Traits> const &xpr) + { + BOOST_ASSERT(0 != xpr.bset_.count()); + this->bset_.set_bitset(xpr.bset_); + return mpl::false_(); + } + + template<typename Matcher, typename Traits, typename ICase> + mpl::false_ accept(attr_matcher<Matcher, Traits, ICase> const &xpr) + { + xpr.sym_.peek(char_sink<Traits, ICase::value>(this->bset_, this->get_traits_<Traits>())); + return mpl::false_(); + } + + template<typename Xpr, typename Greedy> + mpl::false_ accept(optional_matcher<Xpr, Greedy> const &) + { + this->fail(); // a union of xpr and next + return mpl::false_(); + } + + template<typename Xpr, typename Greedy> + mpl::false_ accept(optional_mark_matcher<Xpr, Greedy> const &) + { + this->fail(); // a union of xpr and next + return mpl::false_(); + } + + //template<typename Xpr, typename Greedy> + //mpl::true_ accept(optional_matcher<Xpr, Greedy> const &xpr) + //{ + // xpr.xpr_.peek(*this); // a union of xpr and next + // return mpl::true_(); + //} + + //template<typename Xpr, typename Greedy> + //mpl::true_ accept(optional_mark_matcher<Xpr, Greedy> const &xpr) + //{ + // xpr.xpr_.peek(*this); // a union of xpr and next + // return mpl::true_(); + //} + + template<typename Traits> + mpl::false_ accept(posix_charset_matcher<Traits> const &xpr) + { + this->bset_.set_class(xpr.mask_, xpr.not_, this->get_traits_<Traits>()); + return mpl::false_(); + } + + template<typename ICase, typename Traits> + typename enable_if<is_narrow_char<typename Traits::char_type>, mpl::false_>::type + accept(charset_matcher<Traits, ICase, basic_chset<Char> > const &xpr) + { + BOOST_ASSERT(0 != xpr.charset_.base().count()); + this->bset_.set_charset(xpr.charset_, ICase()); + return mpl::false_(); + } + + template<typename Traits, typename ICase> + mpl::false_ accept(range_matcher<Traits, ICase> const &xpr) + { + this->bset_.set_range(xpr.ch_min_, xpr.ch_max_, xpr.not_, ICase(), this->get_traits_<Traits>()); + return mpl::false_(); + } + + template<typename Xpr, typename Greedy> + mpl::false_ accept(simple_repeat_matcher<Xpr, Greedy> const &xpr) + { + if(Greedy() && 1U == xpr.width_) + { + ++this->leading_simple_repeat_; + xpr.leading_ = this->leading_simple_repeat(); + } + 0 != xpr.min_ ? xpr.xpr_.peek(*this) : this->fail(); // could be a union of xpr and next + return mpl::false_(); + } + + template<typename Xpr> + mpl::false_ accept(keeper_matcher<Xpr> const &xpr) + { + xpr.xpr_.peek(*this); + return mpl::false_(); + } + + template<typename Traits> + void set_traits(Traits const &tr) + { + if(0 == this->traits_) + { + this->traits_ = &tr; + this->traits_type_ = &typeid(Traits); + } + else if(*this->traits_type_ != typeid(Traits) || this->get_traits_<Traits>() != tr) + { + this->fail(); // traits mis-match! set all and bail + } + } + +private: + xpression_peeker(xpression_peeker const &); + xpression_peeker &operator =(xpression_peeker const &); + + template<typename Traits> + Traits const &get_traits_() const + { + BOOST_ASSERT(!!(*this->traits_type_ == typeid(Traits))); + return *static_cast<Traits const *>(this->traits_); + } + + hash_peek_bitset<Char> &bset_; + peeker_string<Char> str_; + bool str_icase_; + bool line_start_; + void const *traits_; + std::type_info const *traits_type_; + int leading_simple_repeat_; + bool has_backrefs_; +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/quant_style.hpp b/boost/xpressive/detail/core/quant_style.hpp new file mode 100644 index 0000000000..ae3b0cfdc7 --- /dev/null +++ b/boost/xpressive/detail/core/quant_style.hpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////// +// quant_style.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_QUANT_STYLE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_QUANT_STYLE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/mpl/has_xxx.hpp> +#include <boost/xpressive/detail/utility/width.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +BOOST_MPL_HAS_XXX_TRAIT_DEF(is_boost_xpressive_xpression_) + +/////////////////////////////////////////////////////////////////////////////// +// is_xpr +// +template<typename Xpr> +struct is_xpr + : has_is_boost_xpressive_xpression_<Xpr> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// quant_enum +// +enum quant_enum +{ + quant_none, + quant_fixed_width, + quant_variable_width +}; + +/////////////////////////////////////////////////////////////////////////////// +// quant_style +// +template<quant_enum QuantStyle, std::size_t Width = unknown_width::value, bool Pure = true> +struct quant_style +{ + typedef void is_boost_xpressive_xpression_; + + // Which quantification strategy to use? + BOOST_STATIC_CONSTANT(int, quant = QuantStyle); + + // how many characters this matcher consumes + BOOST_STATIC_CONSTANT(std::size_t, width = Width); + + // whether this matcher has observable side-effects + BOOST_STATIC_CONSTANT(bool, pure = Pure); + + static detail::width get_width() + { + return width; + } +}; + +#define BOOST_XPR_QUANT_STYLE(Style, Width, Pure) \ + typedef void is_boost_xpressive_xpression_; \ + BOOST_STATIC_CONSTANT(int, quant = Style); \ + BOOST_STATIC_CONSTANT(std::size_t, width = Width); \ + BOOST_STATIC_CONSTANT(bool, pure = Pure); \ + static detail::width get_width() { return width; } \ + /**/ + +// // Replace transmogrify stupidity with rebindable matchers/placeholders +//#define BOOST_XPR_IDENTITY_REBIND(TYPE) \/ +// template<typename BidiIter, typename ICase, typename Traits> \/ +// struct rebind \/ +// { \/ +// typedef TYPE type; \/ +// }; \/ +// /**/ + +/////////////////////////////////////////////////////////////////////////////// +// quant_style_none +// this sub-expression cannot be quantified +typedef quant_style<quant_none> quant_style_none; + +/////////////////////////////////////////////////////////////////////////////// +// quant_style_fixed_unknown_width +// this sub-expression is fixed width for the purpose of quantification, but +// the width cannot be determined at compile time. An example would be the +// string_matcher or the mark_matcher. +typedef quant_style<quant_fixed_width> quant_style_fixed_unknown_width; + +/////////////////////////////////////////////////////////////////////////////// +// quant_style_variable_width +// this sub-expression can match a variable number of characters +typedef quant_style<quant_variable_width> quant_style_variable_width; + +/////////////////////////////////////////////////////////////////////////////// +// quant_style_fixed_width +// for when the sub-expression has a fixed width that is known at compile time +template<std::size_t Width> +struct quant_style_fixed_width + : quant_style<quant_fixed_width, Width> +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// quant_style_assertion +// a zero-width assertion. +struct quant_style_assertion + : quant_style<quant_none, 0> +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// quant_type +// +template<typename Matcher> +struct quant_type + : mpl::int_<Matcher::quant> +{ +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/regex_domain.hpp b/boost/xpressive/detail/core/regex_domain.hpp new file mode 100644 index 0000000000..18f34809be --- /dev/null +++ b/boost/xpressive/detail/core/regex_domain.hpp @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_domain.hpp +/// Contains the definition of the regex_domain type +// +// Copyright 2009 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_REGEX_DOMAIN_HPP_EAN_12_12_2009 +#define BOOST_XPRESSIVE_DETAIL_CORE_REGEX_DOMAIN_HPP_EAN_12_12_2009 + +#include <boost/xpressive/xpressive_fwd.hpp> +#include <boost/proto/traits.hpp> +#include <boost/proto/domain.hpp> +#include <boost/proto/generate.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + struct regex_domain + : proto::domain<proto::default_generator, proto::not_<proto::address_of<proto::_> > > + {}; +}}} + +#endif diff --git a/boost/xpressive/detail/core/regex_impl.hpp b/boost/xpressive/detail/core/regex_impl.hpp new file mode 100644 index 0000000000..8c3194632b --- /dev/null +++ b/boost/xpressive/detail/core/regex_impl.hpp @@ -0,0 +1,212 @@ +/////////////////////////////////////////////////////////////////////////////// +// regex_impl.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_REGEX_IMPL_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_REGEX_IMPL_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <vector> +#include <boost/intrusive_ptr.hpp> +#include <boost/xpressive/regex_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/matchable.hpp> +#include <boost/xpressive/detail/utility/tracking_ptr.hpp> +#include <boost/xpressive/detail/utility/counted_base.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// finder +template<typename BidiIter> +struct finder + : counted_base<finder<BidiIter> > +{ + virtual ~finder() {} + virtual bool ok_for_partial_matches() const { return true; } + virtual bool operator ()(match_state<BidiIter> &state) const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// traits +template<typename Char> +struct traits + : counted_base<traits<Char> > +{ + virtual ~traits() {} + virtual Char tolower(Char ch) const = 0; + virtual Char toupper(Char ch) const = 0; + virtual bool in_range(Char from, Char to, Char ch) const = 0; + virtual int value(Char ch, int radix) const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// named_mark +template<typename Char> +struct named_mark +{ + typedef typename detail::string_type<Char>::type string_type; + + named_mark(string_type name, std::size_t mark_nbr) + : name_(name) + , mark_nbr_(mark_nbr) + {} + + string_type name_; + std::size_t mark_nbr_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// traits_holder +template<typename Traits> +struct traits_holder + : traits<typename Traits::char_type> +{ + typedef typename Traits::char_type char_type; + + explicit traits_holder(Traits const &tr) + : traits_(tr) + { + } + + Traits const &traits() const + { + return this->traits_; + } + + char_type tolower(char_type ch) const + { + return this->tolower_(ch, typename Traits::version_tag()); + } + + char_type toupper(char_type ch) const + { + return this->toupper_(ch, typename Traits::version_tag()); + } + + int value(char_type ch, int radix) const + { + return this->traits_.value(ch, radix); + } + + bool in_range(char_type from, char_type to, char_type ch) const + { + return this->traits_.in_range(from, to, ch); + } + +private: + char_type tolower_(char_type ch, regex_traits_version_1_tag) const + { + return ch; + } + + char_type toupper_(char_type ch, regex_traits_version_1_tag) const + { + return ch; + } + + char_type tolower_(char_type ch, regex_traits_version_2_tag) const + { + return this->traits_.tolower(ch); + } + + char_type toupper_(char_type ch, regex_traits_version_2_tag) const + { + return this->traits_.toupper(ch); + } + + Traits traits_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// regex_impl +// +template<typename BidiIter> +struct regex_impl + : enable_reference_tracking<regex_impl<BidiIter> > +{ + typedef typename iterator_value<BidiIter>::type char_type; + + regex_impl() + : enable_reference_tracking<regex_impl<BidiIter> >() + , xpr_() + , traits_() + , finder_() + , named_marks_() + , mark_count_(0) + , hidden_mark_count_(0) + { + #ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST + ++instances; + #endif + } + + regex_impl(regex_impl<BidiIter> const &that) + : enable_reference_tracking<regex_impl<BidiIter> >(that) + , xpr_(that.xpr_) + , traits_(that.traits_) + , finder_(that.finder_) + , named_marks_(that.named_marks_) + , mark_count_(that.mark_count_) + , hidden_mark_count_(that.hidden_mark_count_) + { + #ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST + ++instances; + #endif + } + + ~regex_impl() + { + #ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST + --instances; + #endif + } + + void swap(regex_impl<BidiIter> &that) + { + enable_reference_tracking<regex_impl<BidiIter> >::swap(that); + this->xpr_.swap(that.xpr_); + this->traits_.swap(that.traits_); + this->finder_.swap(that.finder_); + this->named_marks_.swap(that.named_marks_); + std::swap(this->mark_count_, that.mark_count_); + std::swap(this->hidden_mark_count_, that.hidden_mark_count_); + } + + intrusive_ptr<matchable_ex<BidiIter> const> xpr_; + intrusive_ptr<traits<char_type> const> traits_; + intrusive_ptr<finder<BidiIter> > finder_; + std::vector<named_mark<char_type> > named_marks_; + std::size_t mark_count_; + std::size_t hidden_mark_count_; + + #ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST + static int instances; + #endif + +private: + regex_impl &operator =(regex_impl const &); +}; + +template<typename BidiIter> +void swap(regex_impl<BidiIter> &left, regex_impl<BidiIter> &right) +{ + left.swap(right); +} + +#ifdef BOOST_XPRESSIVE_DEBUG_CYCLE_TEST +template<typename BidiIter> +int regex_impl<BidiIter>::instances = 0; +#endif + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/results_cache.hpp b/boost/xpressive/detail/core/results_cache.hpp new file mode 100644 index 0000000000..702c61e7d3 --- /dev/null +++ b/boost/xpressive/detail/core/results_cache.hpp @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////// +// results_cache.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_RESULTS_CACHE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_RESULTS_CACHE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <cstddef> +#include <boost/detail/workaround.hpp> +#include <boost/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/list.hpp> +#include <boost/xpressive/detail/core/access.hpp> +#include <boost/xpressive/match_results.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // nested_results + #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) + template<typename BidiIter> + struct nested_results + : detail::list<match_results<BidiIter> > + { + friend struct results_cache<BidiIter>; + friend struct match_results<BidiIter>; + }; + #else + template<typename BidiIter> + struct nested_results + : private detail::list<match_results<BidiIter> > + { + friend struct results_cache<BidiIter>; + friend struct xpressive::match_results<BidiIter>; + typedef list<xpressive::match_results<BidiIter> > base_type; + + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::size_type size_type; + using base_type::begin; + using base_type::end; + using base_type::size; + using base_type::empty; + using base_type::front; + using base_type::back; + }; + #endif + + /////////////////////////////////////////////////////////////////////////////// + // results_cache + // + // cache storage for reclaimed match_results structs + template<typename BidiIter> + struct results_cache + { + typedef core_access<BidiIter> access; + + match_results<BidiIter> &append_new(nested_results<BidiIter> &out) + { + if(this->cache_.empty()) + { + out.push_back(match_results<BidiIter>()); + } + else + { + BOOST_ASSERT(access::get_nested_results(this->cache_.back()).empty()); + out.splice(out.end(), this->cache_, --this->cache_.end()); + } + return out.back(); + } + + // move the last match_results struct into the cache + void reclaim_last(nested_results<BidiIter> &out) + { + BOOST_ASSERT(!out.empty()); + // first, reclaim any nested results + nested_results<BidiIter> &nested = access::get_nested_results(out.back()); + if(!nested.empty()) + { + this->reclaim_all(nested); + } + // then, reclaim the last match_results + this->cache_.splice(this->cache_.end(), out, --out.end()); + } + + // move the last n match_results structs into the cache + void reclaim_last_n(nested_results<BidiIter> &out, std::size_t count) + { + for(; 0 != count; --count) + { + this->reclaim_last(out); + } + } + + void reclaim_all(nested_results<BidiIter> &out) + { + typedef typename nested_results<BidiIter>::iterator iter_type; + + // first, recursively reclaim all the nested results + for(iter_type begin = out.begin(); begin != out.end(); ++begin) + { + nested_results<BidiIter> &nested = access::get_nested_results(*begin); + + if(!nested.empty()) + { + this->reclaim_all(nested); + } + } + + // next, reclaim the results themselves + this->cache_.splice(this->cache_.end(), out); + } + + private: + + nested_results<BidiIter> cache_; + }; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/state.hpp b/boost/xpressive/detail/core/state.hpp new file mode 100644 index 0000000000..e20c91572e --- /dev/null +++ b/boost/xpressive/detail/core/state.hpp @@ -0,0 +1,401 @@ +/////////////////////////////////////////////////////////////////////////////// +// state.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_STATE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_STATE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/noncopyable.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/access.hpp> +#include <boost/xpressive/detail/core/action.hpp> +#include <boost/xpressive/detail/core/sub_match_vector.hpp> +#include <boost/xpressive/detail/utility/sequence_stack.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/regex_constants.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// match_context +// +template<typename BidiIter> +struct match_context +{ + typedef typename iterator_value<BidiIter>::type char_type; + + match_context() + : results_ptr_(0) + , prev_context_(0) + , next_ptr_(0) + , traits_(0) + { + } + + // pointer to the current match results, passed to actions as a parameter. + match_results<BidiIter> *results_ptr_; + + // The previous match context, if this match_context corresponds to a nested regex invocation + match_context<BidiIter> *prev_context_; + + // If this is a nested match, the "next" sub-expression to execute after the nested match + matchable<BidiIter> const *next_ptr_; + + // A pointer to the current traits object + detail::traits<char_type> const *traits_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// attr_context +// +struct attr_context +{ + // Slots for holding type-erased pointers to attributes + void const **attr_slots_; + + // The previous attr context, if one exists + attr_context *prev_attr_context_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// match_flags +// +struct match_flags +{ + bool match_all_; + bool match_prev_avail_; + bool match_bol_; + bool match_eol_; + bool match_not_bow_; + bool match_not_eow_; + bool match_not_null_; + bool match_continuous_; + bool match_partial_; + + explicit match_flags(regex_constants::match_flag_type flags) + : match_all_(false) + , match_prev_avail_(0 != (flags & regex_constants::match_prev_avail)) + , match_bol_(match_prev_avail_ || 0 == (flags & regex_constants::match_not_bol)) + , match_eol_(0 == (flags & regex_constants::match_not_eol)) + , match_not_bow_(!match_prev_avail_ && 0 != (flags & regex_constants::match_not_bow)) + , match_not_eow_(0 != (flags & regex_constants::match_not_eow)) + , match_not_null_(0 != (flags & regex_constants::match_not_null)) + , match_continuous_(0 != (flags & regex_constants::match_continuous)) + , match_partial_(0 != (flags & regex_constants::match_partial)) + { + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// match_state +// +template<typename BidiIter> +struct match_state + : noncopyable +{ + typedef BidiIter iterator; + typedef core_access<BidiIter> access; + typedef detail::match_context<BidiIter> match_context; + typedef detail::results_extras<BidiIter> results_extras; + typedef detail::regex_impl<BidiIter> regex_impl; + typedef detail::matchable<BidiIter> matchable; + typedef xpressive::match_results<BidiIter> match_results; + typedef detail::sub_match_impl<BidiIter> sub_match_impl; + typedef detail::actionable actionable; + + BidiIter cur_; + sub_match_impl *sub_matches_; + std::size_t mark_count_; + BidiIter begin_; + BidiIter end_; + + match_flags flags_; + bool found_partial_match_; + + match_context context_; + results_extras *extras_; + actionable action_list_; + actionable const **action_list_tail_; + action_args_type *action_args_; + attr_context attr_context_; + BidiIter next_search_; + + /////////////////////////////////////////////////////////////////////////////// + // + match_state + ( + BidiIter begin + , BidiIter end + , match_results &what + , regex_impl const &impl + , regex_constants::match_flag_type flags + ) + : cur_(begin) + , sub_matches_(0) + , mark_count_(0) + , begin_(begin) + , end_(end) + , flags_(flags) + , found_partial_match_(false) + , context_() // zero-initializes the fields of context_ + , extras_(&core_access<BidiIter>::get_extras(what)) + , action_list_() + , action_list_tail_(&action_list_.next) + , action_args_(&core_access<BidiIter>::get_action_args(what)) + , attr_context_() // zero-initializes the fields of attr_context_ + , next_search_(begin) + { + // reclaim any cached memory in the match_results struct + this->extras_->sub_match_stack_.unwind(); + + // initialize the context_ struct + this->init_(impl, what); + + // move all the nested match_results structs into the match_results cache + this->extras_->results_cache_.reclaim_all(access::get_nested_results(what)); + } + + /////////////////////////////////////////////////////////////////////////////// + // reset + void reset(match_results &what, regex_impl const &impl) + { + this->extras_ = &core_access<BidiIter>::get_extras(what); + this->action_list_.next = 0; + this->action_list_tail_ = &action_list_.next; + this->action_args_ = &core_access<BidiIter>::get_action_args(what); + this->attr_context_ = attr_context(); + this->context_.prev_context_ = 0; + this->found_partial_match_ = false; + this->extras_->sub_match_stack_.unwind(); + this->init_(impl, what); + this->extras_->results_cache_.reclaim_all(access::get_nested_results(what)); + } + + /////////////////////////////////////////////////////////////////////////////// + // push_context + // called to prepare the state object for a regex match + match_context push_context(regex_impl const &impl, matchable const &next, match_context &prev) + { + // save state + match_context context = this->context_; + + // create a new nested match_results for this regex + nested_results<BidiIter> &nested = access::get_nested_results(*context.results_ptr_); + match_results &what = this->extras_->results_cache_.append_new(nested); + + // (re)initialize the match context + this->init_(impl, what); + + // create a linked list of match_context structs + this->context_.prev_context_ = &prev; + this->context_.next_ptr_ = &next; + + // record the start of the zero-th sub-match + this->sub_matches_[0].begin_ = this->cur_; + + return context; + } + + /////////////////////////////////////////////////////////////////////////////// + // pop_context + // called after a nested match failed to restore the context + bool pop_context(regex_impl const &impl, bool success) + { + match_context &context = *this->context_.prev_context_; + if(!success) + { + match_results &what = *context.results_ptr_; + this->uninit_(impl, what); + + // send the match_results struct back to the cache + nested_results<BidiIter> &nested = access::get_nested_results(what); + this->extras_->results_cache_.reclaim_last(nested); + } + + // restore the state + this->context_ = context; + match_results &results = *this->context_.results_ptr_; + this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results)); + this->mark_count_ = results.size(); + return success; + } + + /////////////////////////////////////////////////////////////////////////////// + // swap_context + void swap_context(match_context &context) + { + std::swap(this->context_, context); + match_results &results = *this->context_.results_ptr_; + this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results)); + this->mark_count_ = results.size(); + } + + // beginning of buffer + bool bos() const + { + return this->cur_ == this->begin_; + } + + // end of buffer + bool eos() + { + return this->cur_ == this->end_ && this->found_partial_match(); + } + + // is this the regex that is currently executing? + bool is_active_regex(regex_impl const &impl) const + { + return impl.xpr_.get() == this->context_.results_ptr_->regex_id(); + } + + // fetch the n-th sub_match + sub_match_impl &sub_match(int n) + { + return this->sub_matches_[n]; + } + + // called when a partial match has succeeded + void set_partial_match() + { + sub_match_impl &sub0 = this->sub_match(0); + sub0.first = sub0.begin_; + sub0.second = this->end_; + sub0.matched = false; + } + + template<typename Traits> + Traits const &get_traits() const + { + return static_cast<traits_holder<Traits> const *>(this->context_.traits_)->traits(); + } + +private: + + void init_(regex_impl const &impl, match_results &what) + { + regex_id_type const id = impl.xpr_.get(); + std::size_t const total_mark_count = impl.mark_count_ + impl.hidden_mark_count_ + 1; + + // initialize the context and the sub_match vector + this->context_.results_ptr_ = &what; + this->context_.traits_ = impl.traits_.get(); + this->mark_count_ = impl.mark_count_ + 1; + this->sub_matches_ = this->extras_->sub_match_stack_.push_sequence(total_mark_count, sub_match_impl(begin_), detail::fill); + this->sub_matches_ += impl.hidden_mark_count_; + + // initialize the match_results struct + access::init_match_results(what, id, impl.traits_, this->sub_matches_, this->mark_count_, impl.named_marks_); + } + + void uninit_(regex_impl const &impl, match_results &) + { + extras_->sub_match_stack_.unwind_to(this->sub_matches_ - impl.hidden_mark_count_); + } + + bool found_partial_match() + { + this->found_partial_match_ = true; + return true; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// memento +// +template<typename BidiIter> +struct memento +{ + sub_match_impl<BidiIter> *old_sub_matches_; + std::size_t nested_results_count_; + actionable const *action_list_head_; + actionable const **action_list_tail_; + attr_context attr_context_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// save_sub_matches +// +template<typename BidiIter> +inline memento<BidiIter> save_sub_matches(match_state<BidiIter> &state) +{ + memento<BidiIter> mem = + { + state.extras_->sub_match_stack_.push_sequence(state.mark_count_, sub_match_impl<BidiIter>(state.begin_)) + , state.context_.results_ptr_->nested_results().size() + , state.action_list_.next + , state.action_list_tail_ + , state.attr_context_ + }; + state.action_list_.next = 0; + state.action_list_tail_ = &state.action_list_.next; + std::copy(state.sub_matches_, state.sub_matches_ + state.mark_count_, mem.old_sub_matches_); + return mem; +} + +/////////////////////////////////////////////////////////////////////////////// +// restore_action_queue +// +template<typename BidiIter> +inline void restore_action_queue(memento<BidiIter> const &mem, match_state<BidiIter> &state) +{ + state.action_list_.next = mem.action_list_head_; + state.action_list_tail_ = mem.action_list_tail_; + *state.action_list_tail_ = 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// restore_sub_matches +// +template<typename BidiIter> +inline void restore_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state) +{ + typedef core_access<BidiIter> access; + nested_results<BidiIter> &nested = access::get_nested_results(*state.context_.results_ptr_); + std::size_t count = nested.size() - mem.nested_results_count_; + state.extras_->results_cache_.reclaim_last_n(nested, count); + std::copy(mem.old_sub_matches_, mem.old_sub_matches_ + state.mark_count_, state.sub_matches_); + state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_); + state.attr_context_ = mem.attr_context_; +} + +/////////////////////////////////////////////////////////////////////////////// +// reclaim_sub_matches +// +template<typename BidiIter> +inline void reclaim_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state, bool success) +{ + std::size_t count = state.context_.results_ptr_->nested_results().size() - mem.nested_results_count_; + if(count == 0) + { + state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_); + } + // else we have we must orphan this block of backrefs because we are using the stack + // space above it. + + if(!success) + { + state.attr_context_ = mem.attr_context_; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// traits_cast +// +template<typename Traits, typename BidiIter> +inline Traits const &traits_cast(match_state<BidiIter> const &state) +{ + return state.template get_traits<Traits>(); +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/sub_match_impl.hpp b/boost/xpressive/detail/core/sub_match_impl.hpp new file mode 100644 index 0000000000..0301dd48eb --- /dev/null +++ b/boost/xpressive/detail/core/sub_match_impl.hpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// sub_match_impl.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_SUB_MATCH_IMPL_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_SUB_MATCH_IMPL_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/sub_match.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +// TODO: sub_match_impl is a POD IFF BidiIter is POD. Pool allocation +// of them can be made more efficient if they are. Or maybe all they +// need is trivial constructor/destructor. (???) + +/////////////////////////////////////////////////////////////////////////////// +// sub_match_impl +// +template<typename BidiIter> +struct sub_match_impl + : sub_match<BidiIter> +{ + unsigned int repeat_count_; + BidiIter begin_; + bool zero_width_; + + sub_match_impl(BidiIter const &begin) + : sub_match<BidiIter>(begin, begin) + , repeat_count_(0) + , begin_(begin) + , zero_width_(false) + { + } +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/core/sub_match_vector.hpp b/boost/xpressive/detail/core/sub_match_vector.hpp new file mode 100644 index 0000000000..d10ee7641c --- /dev/null +++ b/boost/xpressive/detail/core/sub_match_vector.hpp @@ -0,0 +1,171 @@ +/////////////////////////////////////////////////////////////////////////////// +// sub_match_vector.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_SUB_MATCH_VECTOR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CORE_SUB_MATCH_VECTOR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/noncopyable.hpp> +#include <boost/iterator_adaptors.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/sub_match_impl.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 + +////////////////////////////////////////////////////////////////////////// +// sub_match_iterator +// +template<typename Value, typename MainIter> +struct sub_match_iterator + : iterator_adaptor + < + sub_match_iterator<Value, MainIter> + , MainIter + , Value + , std::random_access_iterator_tag + > +{ + typedef iterator_adaptor + < + sub_match_iterator<Value, MainIter> + , MainIter + , Value + , std::random_access_iterator_tag + > base_t; + + sub_match_iterator(MainIter baseiter) + : base_t(baseiter) + { + } +}; + +#endif + +////////////////////////////////////////////////////////////////////////// +// sub_match_vector +// +template<typename BidiIter> +struct sub_match_vector + : private noncopyable +{ +private: + struct dummy { int i_; }; + typedef int dummy::*bool_type; + +public: + typedef sub_match<BidiIter> value_type; + typedef std::size_t size_type; + typedef value_type const &const_reference; + typedef const_reference reference; + typedef typename iterator_difference<BidiIter>::type difference_type; + typedef typename iterator_value<BidiIter>::type char_type; + typedef typename sub_match<BidiIter>::string_type string_type; + +#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 + + typedef sub_match_iterator + < + value_type const + , sub_match_impl<BidiIter> const * + > const_iterator; + +#else + + typedef iterator_adaptor + < + sub_match_impl<BidiIter> const * + , default_iterator_policies + , value_type + , value_type const & + , value_type const * + > const_iterator; + +#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 + + typedef const_iterator iterator; + + sub_match_vector() + : size_(0) + , sub_matches_(0) + { + } + + const_reference operator [](size_type index) const + { + static value_type const s_null; + return (index >= this->size_) + ? s_null + : *static_cast<value_type const *>(&this->sub_matches_[ index ]); + } + + size_type size() const + { + return this->size_; + } + + bool empty() const + { + return 0 == this->size(); + } + + const_iterator begin() const + { + return const_iterator(this->sub_matches_); + } + + const_iterator end() const + { + return const_iterator(this->sub_matches_ + this->size_); + } + + operator bool_type() const + { + return (!this->empty() && (*this)[0].matched) ? &dummy::i_ : 0; + } + + bool operator !() const + { + return this->empty() || !(*this)[0].matched; + } + + void swap(sub_match_vector<BidiIter> &that) + { + std::swap(this->size_, that.size_); + std::swap(this->sub_matches_, that.sub_matches_); + } + +private: + friend struct detail::core_access<BidiIter>; + + void init_(sub_match_impl<BidiIter> *sub_matches, size_type size) + { + this->size_ = size; + this->sub_matches_ = sub_matches; + } + + void init_(sub_match_impl<BidiIter> *sub_matches, size_type size, sub_match_vector<BidiIter> const &that) + { + BOOST_ASSERT(size == that.size_); + this->size_ = size; + this->sub_matches_ = sub_matches; + std::copy(that.sub_matches_, that.sub_matches_ + that.size_, this->sub_matches_); + } + + size_type size_; + sub_match_impl<BidiIter> *sub_matches_; +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/detail_fwd.hpp b/boost/xpressive/detail/detail_fwd.hpp new file mode 100644 index 0000000000..52deaae9a8 --- /dev/null +++ b/boost/xpressive/detail/detail_fwd.hpp @@ -0,0 +1,486 @@ +/////////////////////////////////////////////////////////////////////////////// +// detail_fwd.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_DETAIL_FWD_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DETAIL_FWD_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <map> +#include <string> +#include <vector> +#include <climits> // for INT_MAX +#include <typeinfo> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/size_t.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/xpressive/xpressive_fwd.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + typedef unsigned int uint_t; + + template<uint_t Min, uint_t Max = Min> + struct generic_quant_tag; + + struct modifier_tag; + + struct check_tag; + + typedef mpl::size_t<INT_MAX / 2 - 1> unknown_width; + + struct type_info_less; + + typedef std::map<std::type_info const *, void *, type_info_less> action_args_type; + + struct action_context; + + struct ReplaceAlgo; + + /////////////////////////////////////////////////////////////////////////////// + // placeholders + // + struct mark_placeholder; + + struct posix_charset_placeholder; + + template<typename Cond> + struct assert_word_placeholder; + + template<typename Char> + struct range_placeholder; + + struct assert_bol_placeholder; + + struct assert_eol_placeholder; + + struct logical_newline_placeholder; + + struct self_placeholder; + + template<typename Nbr> + struct attribute_placeholder; + + /////////////////////////////////////////////////////////////////////////////// + // matchers + // + struct end_matcher; + + struct independent_end_matcher; + + struct assert_bos_matcher; + + struct assert_eos_matcher; + + template<typename Traits> + struct assert_bol_matcher; + + template<typename Traits> + struct assert_eol_matcher; + + template<typename Cond, typename Traits> + struct assert_word_matcher; + + struct true_matcher; + + template<typename Alternates, typename Traits> + struct alternate_matcher; + + struct alternate_end_matcher; + + template<typename Traits> + struct posix_charset_matcher; + + template<typename BidiIter> + struct sequence; + + template<typename Traits, typename ICase> + struct mark_matcher; + + struct mark_begin_matcher; + + struct mark_end_matcher; + + template<typename BidiIter> + struct regex_matcher; + + template<typename BidiIter> + struct regex_byref_matcher; + + template<typename Traits> + struct compound_charset; + + template<typename Traits, typename ICase, typename CharSet = compound_charset<Traits> > + struct charset_matcher; + + template<typename Traits, typename ICase> + struct range_matcher; + + template<typename Traits, typename Size> + struct set_matcher; + + template<typename Xpr, typename Greedy> + struct simple_repeat_matcher; + + struct repeat_begin_matcher; + + template<typename Greedy> + struct repeat_end_matcher; + + template<typename Traits, typename ICase, typename Not> + struct literal_matcher; + + template<typename Traits, typename ICase> + struct string_matcher; + + template<typename Actor> + struct action_matcher; + + template<typename Predicate> + struct predicate_matcher; + + template<typename Xpr, typename Greedy> + struct optional_matcher; + + template<typename Xpr, typename Greedy> + struct optional_mark_matcher; + + template<typename Matcher, typename Traits, typename ICase> + struct attr_matcher; + + template<typename Nbr> + struct attr_begin_matcher; + + struct attr_end_matcher; + + template<typename Xpr> + struct is_modifiable; + + template<typename Head, typename Tail> + struct alternates_list; + + template<typename Modifier> + struct modifier_op; + + struct icase_modifier; + + template<typename BidiIter, typename ICase, typename Traits> + struct xpression_visitor; + + template<typename BidiIter> + struct regex_impl; + + struct epsilon_matcher; + + template<typename BidiIter> + struct nested_results; + + template<typename BidiIter> + struct regex_id_filter_predicate; + + template<typename Xpr> + struct keeper_matcher; + + template<typename Xpr> + struct lookahead_matcher; + + template<typename Xpr> + struct lookbehind_matcher; + + template<typename IsBoundary> + struct word_boundary; + + template<typename BidiIter, typename Matcher> + sequence<BidiIter> make_dynamic(Matcher const &matcher); + + template<typename Char> + struct xpression_linker; + + template<typename Char> + struct xpression_peeker; + + struct any_matcher; + + template<typename Traits> + struct logical_newline_matcher; + + typedef proto::expr<proto::tag::terminal, proto::term<logical_newline_placeholder>, 0> logical_newline_xpression; + + struct set_initializer; + + typedef proto::expr<proto::tag::terminal, proto::term<set_initializer>, 0> set_initializer_type; + + struct lookahead_tag; + + struct lookbehind_tag; + + struct keeper_tag; + + template<typename Locale> + struct locale_modifier; + + template<typename Matcher> + struct matcher_wrapper; + + template<typename Locale, typename BidiIter> + struct regex_traits_type; + + template<typename Expr> + struct let_; + + template<typename Args, typename BidiIter> + void bind_args(let_<Args> const &, match_results<BidiIter> &); + + /////////////////////////////////////////////////////////////////////////////// + // Misc. + struct no_next; + + template<typename BidiIter> + struct core_access; + + template<typename BidiIter> + struct match_state; + + template<typename BidiIter> + struct matchable; + + template<typename BidiIter> + struct matchable_ex; + + template<typename Matcher, typename BidiIter> + struct dynamic_xpression; + + template<typename BidiIter> + struct shared_matchable; + + template<typename BidiIter> + struct alternates_vector; + + template<typename Matcher, typename Next> + struct static_xpression; + + typedef static_xpression<end_matcher, no_next> end_xpression; + + typedef static_xpression<alternate_end_matcher, no_next> alternate_end_xpression; + + typedef static_xpression<independent_end_matcher, no_next> independent_end_xpression; + + typedef static_xpression<true_matcher, no_next> true_xpression; + + template<typename Matcher, typename Next = end_xpression> + struct static_xpression; + + template<typename Top, typename Next> + struct stacked_xpression; + + template<typename Xpr> + struct is_static_xpression; + + template<typename BidiIter> + struct sub_match_impl; + + template<typename T> + struct list; + + template<typename BidiIter> + struct results_cache; + + template<typename T> + struct sequence_stack; + + template<typename BidiIter> + struct results_extras; + + template<typename BidiIter> + struct match_context; + + template<typename BidiIter> + struct sub_match_vector; + + template<typename T, typename U> + struct action_arg; + + struct actionable; + + template<typename Char> + struct traits; + + template<typename Traits, typename BidiIter> + Traits const &traits_cast(match_state<BidiIter> const &state); + + template<typename Char> + struct basic_chset; + + template<typename Char> + struct named_mark; + + template<typename BidiIter> + struct memento; + + template<typename Char, typename Traits> + void set_char(compound_charset<Traits> &chset, Char ch, Traits const &tr, bool icase); + + template<typename Char, typename Traits> + void set_range(compound_charset<Traits> &chset, Char from, Char to, Traits const &tr, bool icase); + + template<typename Traits> + void set_class(compound_charset<Traits> &chset, typename Traits::char_class_type char_class, bool no, Traits const &tr); + + template<typename Char, typename Traits> + void set_char(basic_chset<Char> &chset, Char ch, Traits const &tr, bool icase); + + template<typename Char, typename Traits> + void set_range(basic_chset<Char> &chset, Char from, Char to, Traits const &tr, bool icase); + + template<typename Char, typename Traits> + void set_class(basic_chset<Char> &chset, typename Traits::char_class_type char_class, bool no, Traits const &tr); + + template<typename Matcher> + static_xpression<Matcher> const + make_static(Matcher const &matcher); + + template<typename Matcher, typename Next> + static_xpression<Matcher, Next> const + make_static(Matcher const &matcher, Next const &next); + + int get_mark_number(basic_mark_tag const &); + + template<typename Xpr, typename BidiIter> + void static_compile(Xpr const &xpr, shared_ptr<regex_impl<BidiIter> > const &impl); + + struct quant_spec; + + template<typename BidiIter, typename Xpr> + void make_simple_repeat(quant_spec const &spec, sequence<BidiIter> &seq, Xpr const &xpr); + + template<typename BidiIter> + void make_simple_repeat(quant_spec const &spec, sequence<BidiIter> &seq); + + template<typename BidiIter> + void make_repeat(quant_spec const &spec, sequence<BidiIter> &seq, int mark_nbr); + + template<typename BidiIter> + void make_repeat(quant_spec const &spec, sequence<BidiIter> &seq); + + template<typename BidiIter> + void make_optional(quant_spec const &spec, sequence<BidiIter> &seq); + + template<typename BidiIter> + void make_optional(quant_spec const &spec, sequence<BidiIter> &seq, int mark_nbr); + + template<typename Char> + struct string_type + { + typedef std::vector<Char> type; + }; + + template<> + struct string_type<char> + { + typedef std::string type; + }; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + template<> + struct string_type<wchar_t> + { + typedef std::wstring type; + }; + #endif + +}}} // namespace boost::xpressive::detail + +namespace boost { namespace xpressive { namespace grammar_detail +{ + using proto::_; + using proto::or_; + using proto::if_; + using proto::call; + using proto::when; + using proto::otherwise; + using proto::switch_; + using proto::make; + using proto::_child; + using proto::_value; + using proto::_left; + using proto::_right; + using proto::not_; + using proto::_state; + using proto::_data; + using proto::callable; + using proto::transform; + using proto::fold; + using proto::reverse_fold; + using proto::fold_tree; + using proto::reverse_fold_tree; + using proto::terminal; + using proto::shift_right; + using proto::bitwise_or; + using proto::logical_not; + using proto::dereference; + using proto::unary_plus; + using proto::negate; + using proto::complement; + using proto::comma; + using proto::assign; + using proto::subscript; + using proto::nary_expr; + using proto::unary_expr; + using proto::binary_expr; + using proto::_deep_copy; + using proto::vararg; + namespace tag = proto::tag; +}}} + +namespace boost { namespace xpressive { namespace op +{ + struct push; + struct push_back; + struct pop; + struct push_front; + struct pop_back; + struct pop_front; + struct back; + struct front; + struct top; + struct first; + struct second; + struct matched; + struct length; + struct str; + struct insert; + struct make_pair; + + template<typename T> + struct as; + template<typename T> + struct static_cast_; + template<typename T> + struct dynamic_cast_; + template<typename T> + struct const_cast_; + template<typename T> + struct construct; + template<typename T> + struct throw_; +}}} // namespace boost::xpressive::op + +/// INTERNAL ONLY +namespace boost { namespace xpressive +{ + + /// INTERNAL ONLY + template<typename Traits, std::size_t N> + typename Traits::char_class_type + lookup_classname(Traits const &traits, char const (&cname)[N], bool icase = false); + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/detail/dynamic/dynamic.hpp b/boost/xpressive/detail/dynamic/dynamic.hpp new file mode 100644 index 0000000000..afbff0c145 --- /dev/null +++ b/boost/xpressive/detail/dynamic/dynamic.hpp @@ -0,0 +1,337 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/boost/xpressive/detail/dynamic/matchable.hpp b/boost/xpressive/detail/dynamic/matchable.hpp new file mode 100644 index 0000000000..320bc698af --- /dev/null +++ b/boost/xpressive/detail/dynamic/matchable.hpp @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +// matchable.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_MATCHABLE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_MATCHABLE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/utility/counted_base.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/sequence.hpp> +#include <boost/xpressive/regex_error.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +////////////////////////////////////////////////////////////////////////// +// quant_spec +struct quant_spec +{ + unsigned int min_; + unsigned int max_; + bool greedy_; + std::size_t *hidden_mark_count_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// matchable +template<typename BidiIter> +struct matchable +{ + typedef BidiIter iterator_type; + typedef typename iterator_value<iterator_type>::type char_type; + virtual ~matchable() {} + virtual bool match(match_state<BidiIter> &state) const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// matchable_ex +template<typename BidiIter> +struct matchable_ex + : matchable<BidiIter> + , counted_base<matchable_ex<BidiIter> > +{ + typedef BidiIter iterator_type; + typedef typename iterator_value<iterator_type>::type char_type; + + virtual void link(xpression_linker<char_type> &) const + { + } + + virtual void peek(xpression_peeker<char_type> &peeker) const + { + peeker.fail(); + } + + virtual void repeat(quant_spec const &, sequence<BidiIter> &) const + { + BOOST_THROW_EXCEPTION( + regex_error(regex_constants::error_badrepeat, "expression cannot be quantified") + ); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // The following 4 functions (push_match, top_match, pop_match and skip_match) are + // used to implement looping and branching across the matchers. Call push_match to record + // a position. Then, another matcher further down the xpression chain has the + // option to call either top_match, pop_match or skip_match. top_match and pop_match will + // jump back to the place recorded by push_match, whereas skip_match will skip the jump and + // pass execution down the xpression chain. top_match will leave the xpression on top of the + // stack, whereas pop_match will remove it. Each function comes in 2 flavors: one for + // statically bound xpressions and one for dynamically bound xpressions. + // + + template<typename Top> + bool push_match(match_state<BidiIter> &state) const + { + BOOST_MPL_ASSERT((is_same<Top, matchable_ex<BidiIter> >)); + return this->match(state); + } + + static bool top_match(match_state<BidiIter> &state, void const *top) + { + return static_cast<matchable_ex<BidiIter> const *>(top)->match(state); + } + + static bool pop_match(match_state<BidiIter> &state, void const *top) + { + return static_cast<matchable_ex<BidiIter> const *>(top)->match(state); + } + + bool skip_match(match_state<BidiIter> &state) const + { + return this->match(state); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// shared_matchable +template<typename BidiIter> +struct shared_matchable +{ + typedef BidiIter iterator_type; + typedef typename iterator_value<BidiIter>::type char_type; + typedef intrusive_ptr<matchable_ex<BidiIter> const> matchable_ptr; + + BOOST_STATIC_CONSTANT(std::size_t, width = unknown_width::value); + BOOST_STATIC_CONSTANT(bool, pure = false); + + shared_matchable(matchable_ptr const &xpr = matchable_ptr()) + : xpr_(xpr) + { + } + + bool operator !() const + { + return !this->xpr_; + } + + friend bool operator ==(shared_matchable<BidiIter> const &left, shared_matchable<BidiIter> const &right) + { + return left.xpr_ == right.xpr_; + } + + friend bool operator !=(shared_matchable<BidiIter> const &left, shared_matchable<BidiIter> const &right) + { + return left.xpr_ != right.xpr_; + } + + matchable_ptr const &matchable() const + { + return this->xpr_; + } + + bool match(match_state<BidiIter> &state) const + { + return this->xpr_->match(state); + } + + void link(xpression_linker<char_type> &linker) const + { + this->xpr_->link(linker); + } + + void peek(xpression_peeker<char_type> &peeker) const + { + this->xpr_->peek(peeker); + } + + // BUGBUG yuk! + template<typename Top> + bool push_match(match_state<BidiIter> &state) const + { + BOOST_MPL_ASSERT((is_same<Top, matchable_ex<BidiIter> >)); + return this->match(state); + } + +private: + matchable_ptr xpr_; +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/dynamic/parse_charset.hpp b/boost/xpressive/detail/dynamic/parse_charset.hpp new file mode 100644 index 0000000000..d4e3671d4b --- /dev/null +++ b/boost/xpressive/detail/dynamic/parse_charset.hpp @@ -0,0 +1,365 @@ +/////////////////////////////////////////////////////////////////////////////// +// parse_charset.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_PARSE_CHARSET_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_PARSE_CHARSET_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/integer.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/throw_exception.hpp> +#include <boost/numeric/conversion/converter.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/parser_enum.hpp> +#include <boost/xpressive/detail/utility/literals.hpp> +#include <boost/xpressive/detail/utility/chset/chset.hpp> +#include <boost/xpressive/regex_constants.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +enum escape_type +{ + escape_char + , escape_mark + , escape_class +}; + +/////////////////////////////////////////////////////////////////////////////// +// escape_value +// +template<typename Char, typename Class> +struct escape_value +{ + Char ch_; + int mark_nbr_; + Class class_; + escape_type type_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// char_overflow_handler +// +struct char_overflow_handler +{ + void operator ()(numeric::range_check_result result) const // throw(regex_error) + { + if(numeric::cInRange != result) + { + BOOST_THROW_EXCEPTION( + regex_error( + regex_constants::error_escape + , "character escape too large to fit in target character type" + ) + ); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// parse_escape +// +template<typename FwdIter, typename CompilerTraits> +escape_value<typename iterator_value<FwdIter>::type, typename CompilerTraits::regex_traits::char_class_type> +parse_escape(FwdIter &begin, FwdIter end, CompilerTraits &tr) +{ + using namespace regex_constants; + typedef typename iterator_value<FwdIter>::type char_type; + typedef typename CompilerTraits::regex_traits regex_traits; + typedef typename regex_traits::char_class_type char_class_type; + + // define an unsigned type the same size as char_type + typedef typename boost::uint_t<CHAR_BIT * sizeof(char_type)>::least uchar_t; + BOOST_MPL_ASSERT_RELATION(sizeof(uchar_t), ==, sizeof(char_type)); + typedef numeric::conversion_traits<uchar_t, int> converstion_traits; + + BOOST_XPR_ENSURE_(begin != end, error_escape, "unexpected end of pattern found"); + numeric::converter<int, uchar_t, converstion_traits, char_overflow_handler> converter; + escape_value<char_type,char_class_type> esc = { 0, 0, 0, escape_char }; + bool const icase = (0 != (regex_constants::icase_ & tr.flags())); + regex_traits const &rxtraits = tr.traits(); + FwdIter tmp; + + esc.class_ = rxtraits.lookup_classname(begin, begin + 1, icase); + if(0 != esc.class_) + { + esc.type_ = escape_class; + return esc; + } + + if(-1 != rxtraits.value(*begin, 8)) + { + esc.ch_ = converter(toi(begin, end, rxtraits, 8, 0777)); + return esc; + } + + switch(*begin) + { + // bell character + case BOOST_XPR_CHAR_(char_type, 'a'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\a'); + ++begin; + break; + // escape character + case BOOST_XPR_CHAR_(char_type, 'e'): + esc.ch_ = converter(27); + ++begin; + break; + // control character + case BOOST_XPR_CHAR_(char_type, 'c'): + BOOST_XPR_ENSURE_(++begin != end, error_escape, "unexpected end of pattern found"); + BOOST_XPR_ENSURE_ + ( + rxtraits.in_range(BOOST_XPR_CHAR_(char_type, 'a'), BOOST_XPR_CHAR_(char_type, 'z'), *begin) + || rxtraits.in_range(BOOST_XPR_CHAR_(char_type, 'A'), BOOST_XPR_CHAR_(char_type, 'Z'), *begin) + , error_escape + , "invalid escape control letter; must be one of a-z or A-Z" + ); + // Convert to character according to ECMA-262, section 15.10.2.10: + esc.ch_ = converter(*begin % 32); + ++begin; + break; + // formfeed character + case BOOST_XPR_CHAR_(char_type, 'f'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\f'); + ++begin; + break; + // newline + case BOOST_XPR_CHAR_(char_type, 'n'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\n'); + ++begin; + break; + // return + case BOOST_XPR_CHAR_(char_type, 'r'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\r'); + ++begin; + break; + // horizontal tab + case BOOST_XPR_CHAR_(char_type, 't'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\t'); + ++begin; + break; + // vertical tab + case BOOST_XPR_CHAR_(char_type, 'v'): + esc.ch_ = BOOST_XPR_CHAR_(char_type, '\v'); + ++begin; + break; + // hex escape sequence + case BOOST_XPR_CHAR_(char_type, 'x'): + BOOST_XPR_ENSURE_(++begin != end, error_escape, "unexpected end of pattern found"); + tmp = begin; + esc.ch_ = converter(toi(begin, end, rxtraits, 16, 0xff)); + BOOST_XPR_ENSURE_(2 == std::distance(tmp, begin), error_escape, "invalid hex escape : " + "must be \\x HexDigit HexDigit"); + break; + // Unicode escape sequence + case BOOST_XPR_CHAR_(char_type, 'u'): + BOOST_XPR_ENSURE_(++begin != end, error_escape, "unexpected end of pattern found"); + tmp = begin; + esc.ch_ = converter(toi(begin, end, rxtraits, 16, 0xffff)); + BOOST_XPR_ENSURE_(4 == std::distance(tmp, begin), error_escape, "invalid Unicode escape : " + "must be \\u HexDigit HexDigit HexDigit HexDigit"); + break; + // backslash + case BOOST_XPR_CHAR_(char_type, '\\'): + //esc.ch_ = BOOST_XPR_CHAR_(char_type, '\\'); + //++begin; + //break; + // all other escaped characters represent themselves + default: + esc.ch_ = *begin; + ++begin; + break; + } + + return esc; +} + +////////////////////////////////////////////////////////////////////////// +// parse_charset +// +template<typename FwdIter, typename RegexTraits, typename CompilerTraits> +inline void parse_charset +( + FwdIter &begin + , FwdIter end + , compound_charset<RegexTraits> &chset + , CompilerTraits &tr +) +{ + using namespace regex_constants; + typedef typename RegexTraits::char_type char_type; + typedef typename RegexTraits::char_class_type char_class_type; + BOOST_ASSERT(begin != end); + RegexTraits const &rxtraits = tr.traits(); + bool const icase = (0 != (regex_constants::icase_ & tr.flags())); + FwdIter iprev = FwdIter(); + escape_value<char_type, char_class_type> esc = {0, 0, 0, escape_char}; + bool invert = false; + + // check to see if we have an inverse charset + if(begin != end && token_charset_invert == tr.get_charset_token(iprev = begin, end)) + { + begin = iprev; + invert = true; + } + + // skip the end token if-and-only-if it is the first token in the charset + if(begin != end && token_charset_end == tr.get_charset_token(iprev = begin, end)) + { + for(; begin != iprev; ++begin) + { + chset.set_char(*begin, rxtraits, icase); + } + } + + compiler_token_type tok; + char_type ch_prev = char_type(), ch_next = char_type(); + bool have_prev = false; + + BOOST_XPR_ENSURE_(begin != end, error_brack, "unexpected end of pattern found"); + + // remember the current position and grab the next token + iprev = begin; + tok = tr.get_charset_token(begin, end); + do + { + BOOST_XPR_ENSURE_(begin != end, error_brack, "unexpected end of pattern found"); + + if(token_charset_hyphen == tok && have_prev) + { + // remember the current position + FwdIter iprev2 = begin; + have_prev = false; + + // ch_prev is lower bound of a range + switch(tr.get_charset_token(begin, end)) + { + case token_charset_hyphen: + case token_charset_invert: + begin = iprev2; // un-get these tokens and fall through + case token_literal: + ch_next = *begin++; + BOOST_XPR_ENSURE_(ch_prev <= ch_next, error_range, "invalid charset range"); + chset.set_range(ch_prev, ch_next, rxtraits, icase); + continue; + case token_charset_backspace: + ch_next = char_type(8); // backspace + BOOST_XPR_ENSURE_(ch_prev <= ch_next, error_range, "invalid charset range"); + chset.set_range(ch_prev, ch_next, rxtraits, icase); + continue; + case token_escape: + esc = parse_escape(begin, end, tr); + if(escape_char == esc.type_) + { + BOOST_XPR_ENSURE_(ch_prev <= esc.ch_, error_range, "invalid charset range"); + chset.set_range(ch_prev, esc.ch_, rxtraits, icase); + continue; + } + case token_charset_end: // fall through + default: // not a range. + begin = iprev; // backup to hyphen token + chset.set_char(ch_prev, rxtraits, icase); + chset.set_char(*begin++, rxtraits, icase); + continue; + } + } + + if(have_prev) + { + chset.set_char(ch_prev, rxtraits, icase); + have_prev = false; + } + + switch(tok) + { + case token_charset_hyphen: + case token_charset_invert: + case token_charset_end: + case token_posix_charset_end: + begin = iprev; // un-get these tokens + ch_prev = *begin++; + have_prev = true; + continue; + + case token_charset_backspace: + ch_prev = char_type(8); // backspace + have_prev = true; + continue; + + case token_posix_charset_begin: + { + FwdIter tmp = begin, start = begin; + bool invert = (token_charset_invert == tr.get_charset_token(tmp, end)); + if(invert) + { + begin = start = tmp; + } + while(token_literal == (tok = tr.get_charset_token(begin, end))) + { + tmp = ++begin; + BOOST_XPR_ENSURE_(begin != end, error_brack, "unexpected end of pattern found"); + } + if(token_posix_charset_end == tok) + { + char_class_type chclass = rxtraits.lookup_classname(start, tmp, icase); + BOOST_XPR_ENSURE_(0 != chclass, error_ctype, "unknown class name"); + chset.set_class(chclass, invert); + continue; + } + begin = iprev; // un-get this token + ch_prev = *begin++; + have_prev = true; + } + continue; + + case token_escape: + esc = parse_escape(begin, end, tr); + if(escape_char == esc.type_) + { + ch_prev = esc.ch_; + have_prev = true; + } + else if(escape_class == esc.type_) + { + char_class_type upper_ = lookup_classname(rxtraits, "upper"); + BOOST_ASSERT(0 != upper_); + chset.set_class(esc.class_, rxtraits.isctype(*begin++, upper_)); + } + else + { + BOOST_ASSERT(false); + } + continue; + + default: + ch_prev = *begin++; + have_prev = true; + continue; + } + } + while(BOOST_XPR_ENSURE_((iprev = begin) != end, error_brack, "unexpected end of pattern found"), + token_charset_end != (tok = tr.get_charset_token(begin, end))); + + if(have_prev) + { + chset.set_char(ch_prev, rxtraits, icase); + } + + if(invert) + { + chset.inverse(); + } +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/dynamic/parser.hpp b/boost/xpressive/detail/dynamic/parser.hpp new file mode 100644 index 0000000000..0c25f33346 --- /dev/null +++ b/boost/xpressive/detail/dynamic/parser.hpp @@ -0,0 +1,360 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file parser.hpp +/// Contains the definition of regex_compiler, a factory for building regex objects +/// from strings. +// +// 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_PARSER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_PARSER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4127) // conditional expression is constant +#endif + +#include <boost/assert.hpp> +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/matchers.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> +#include <boost/xpressive/detail/dynamic/dynamic.hpp> + +// The Regular Expression grammar, in pseudo BNF: +// +// expression = alternates ; +// +// alternates = sequence, *('|', sequence) ; +// +// sequence = quant, *(quant) ; +// +// quant = atom, [*+?] ; +// +// atom = literal | +// '.' | +// '\' any | +// '(' expression ')' ; +// +// literal = not a meta-character ; +// + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// make_char_xpression +// +template<typename BidiIter, typename Char, typename Traits> +inline sequence<BidiIter> make_char_xpression +( + Char ch + , regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + if(0 != (regex_constants::icase_ & flags)) + { + literal_matcher<Traits, mpl::true_, mpl::false_> matcher(ch, tr); + return make_dynamic<BidiIter>(matcher); + } + else + { + literal_matcher<Traits, mpl::false_, mpl::false_> matcher(ch, tr); + return make_dynamic<BidiIter>(matcher); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_any_xpression +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_any_xpression +( + regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + using namespace regex_constants; + typedef typename iterator_value<BidiIter>::type char_type; + typedef detail::set_matcher<Traits, mpl::int_<2> > set_matcher; + typedef literal_matcher<Traits, mpl::false_, mpl::true_> literal_matcher; + + char_type const newline = tr.widen('\n'); + set_matcher s; + s.set_[0] = newline; + s.set_[1] = 0; + s.inverse(); + + switch(((int)not_dot_newline | not_dot_null) & flags) + { + case not_dot_null: + return make_dynamic<BidiIter>(literal_matcher(char_type(0), tr)); + + case not_dot_newline: + return make_dynamic<BidiIter>(literal_matcher(newline, tr)); + + case (int)not_dot_newline | not_dot_null: + return make_dynamic<BidiIter>(s); + + default: + return make_dynamic<BidiIter>(any_matcher()); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_literal_xpression +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_literal_xpression +( + typename Traits::string_type const &literal + , regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + BOOST_ASSERT(0 != literal.size()); + if(1 == literal.size()) + { + return make_char_xpression<BidiIter>(literal[0], flags, tr); + } + + if(0 != (regex_constants::icase_ & flags)) + { + string_matcher<Traits, mpl::true_> matcher(literal, tr); + return make_dynamic<BidiIter>(matcher); + } + else + { + string_matcher<Traits, mpl::false_> matcher(literal, tr); + return make_dynamic<BidiIter>(matcher); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_backref_xpression +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_backref_xpression +( + int mark_nbr + , regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + if(0 != (regex_constants::icase_ & flags)) + { + return make_dynamic<BidiIter> + ( + mark_matcher<Traits, mpl::true_>(mark_nbr, tr) + ); + } + else + { + return make_dynamic<BidiIter> + ( + mark_matcher<Traits, mpl::false_>(mark_nbr, tr) + ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// merge_charset +// +template<typename Char, typename Traits> +inline void merge_charset +( + basic_chset<Char> &basic + , compound_charset<Traits> const &compound + , Traits const &tr +) +{ + detail::ignore_unused(tr); + if(0 != compound.posix_yes()) + { + typename Traits::char_class_type mask = compound.posix_yes(); + for(int i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) + { + if(tr.isctype((Char)i, mask)) + { + basic.set((Char)i); + } + } + } + + if(!compound.posix_no().empty()) + { + for(std::size_t j = 0; j < compound.posix_no().size(); ++j) + { + typename Traits::char_class_type mask = compound.posix_no()[j]; + for(int i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) + { + if(!tr.isctype((Char)i, mask)) + { + basic.set((Char)i); + } + } + } + } + + if(compound.is_inverted()) + { + basic.inverse(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_charset_xpression +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_charset_xpression +( + compound_charset<Traits> &chset + , Traits const &tr + , regex_constants::syntax_option_type flags +) +{ + typedef typename Traits::char_type char_type; + bool const icase = (0 != (regex_constants::icase_ & flags)); + bool const optimize = is_narrow_char<char_type>::value && 0 != (regex_constants::optimize & flags); + + // don't care about compile speed -- fold eveything into a bitset<256> + if(optimize) + { + typedef basic_chset<char_type> charset_type; + charset_type charset(chset.base()); + if(icase) + { + charset_matcher<Traits, mpl::true_, charset_type> matcher(charset); + merge_charset(matcher.charset_, chset, tr); + return make_dynamic<BidiIter>(matcher); + } + else + { + charset_matcher<Traits, mpl::false_, charset_type> matcher(charset); + merge_charset(matcher.charset_, chset, tr); + return make_dynamic<BidiIter>(matcher); + } + } + + // special case to make [[:digit:]] fast + else if(chset.base().empty() && chset.posix_no().empty()) + { + BOOST_ASSERT(0 != chset.posix_yes()); + posix_charset_matcher<Traits> matcher(chset.posix_yes(), chset.is_inverted()); + return make_dynamic<BidiIter>(matcher); + } + + // default, slow + else + { + if(icase) + { + charset_matcher<Traits, mpl::true_> matcher(chset); + return make_dynamic<BidiIter>(matcher); + } + else + { + charset_matcher<Traits, mpl::false_> matcher(chset); + return make_dynamic<BidiIter>(matcher); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_posix_charset_xpression +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_posix_charset_xpression +( + typename Traits::char_class_type m + , bool no + , regex_constants::syntax_option_type //flags + , Traits const & //traits +) +{ + posix_charset_matcher<Traits> charset(m, no); + return make_dynamic<BidiIter>(charset); +} + +/////////////////////////////////////////////////////////////////////////////// +// make_assert_begin_line +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_assert_begin_line +( + regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + if(0 != (regex_constants::single_line & flags)) + { + return detail::make_dynamic<BidiIter>(detail::assert_bos_matcher()); + } + else + { + detail::assert_bol_matcher<Traits> matcher(tr); + return detail::make_dynamic<BidiIter>(matcher); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_assert_end_line +// +template<typename BidiIter, typename Traits> +inline sequence<BidiIter> make_assert_end_line +( + regex_constants::syntax_option_type flags + , Traits const &tr +) +{ + if(0 != (regex_constants::single_line & flags)) + { + return detail::make_dynamic<BidiIter>(detail::assert_eos_matcher()); + } + else + { + detail::assert_eol_matcher<Traits> matcher(tr); + return detail::make_dynamic<BidiIter>(matcher); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// make_assert_word +// +template<typename BidiIter, typename Cond, typename Traits> +inline sequence<BidiIter> make_assert_word(Cond, Traits const &tr) +{ + typedef typename iterator_value<BidiIter>::type char_type; + return detail::make_dynamic<BidiIter> + ( + detail::assert_word_matcher<Cond, Traits>(tr) + ); +} + +/////////////////////////////////////////////////////////////////////////////// +// make_independent_end_xpression +// +template<typename BidiIter> +inline sequence<BidiIter> make_independent_end_xpression(bool pure) +{ + if(pure) + { + return detail::make_dynamic<BidiIter>(detail::true_matcher()); + } + else + { + return detail::make_dynamic<BidiIter>(detail::independent_end_matcher()); + } +} + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/dynamic/parser_enum.hpp b/boost/xpressive/detail/dynamic/parser_enum.hpp new file mode 100644 index 0000000000..521f723b11 --- /dev/null +++ b/boost/xpressive/detail/dynamic/parser_enum.hpp @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////// +// parser_enum.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_PARSER_ENUM_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_PARSER_ENUM_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +namespace boost { namespace xpressive { namespace regex_constants +{ + +/////////////////////////////////////////////////////////////////////////////// +// compiler_token_type +// +enum compiler_token_type +{ + token_literal, + token_any, // . + token_escape, // + token_group_begin, // ( + token_group_end, // ) + token_alternate, // | + token_invalid_quantifier, // { + token_charset_begin, // [ + token_charset_end, // ] + token_charset_invert, // ^ + token_charset_hyphen, // - + token_charset_backspace, // \b + token_posix_charset_begin, // [: + token_posix_charset_end, // :] + token_equivalence_class_begin, // [= + token_equivalence_class_end, // =] + token_collation_element_begin, // [. + token_collation_element_end, // .] + + token_quote_meta_begin, // \Q + token_quote_meta_end, // \E + + token_no_mark, // ?: + token_positive_lookahead, // ?= + token_negative_lookahead, // ?! + token_positive_lookbehind, // ?<= + token_negative_lookbehind, // ?<! + token_independent_sub_expression, // ?> + token_comment, // ?# + token_recurse, // ?R + token_rule_assign, // ?$[name]= + token_rule_ref, // ?$[name] + token_named_mark, // ?P<name> + token_named_mark_ref, // ?P=name + + token_assert_begin_sequence, // \A + token_assert_end_sequence, // \Z + token_assert_begin_line, // ^ + token_assert_end_line, // $ + token_assert_word_begin, // \< + token_assert_word_end, // \> + token_assert_word_boundary, // \b + token_assert_not_word_boundary, // \B + + token_escape_newline, // \n + token_escape_escape, // \e + token_escape_formfeed, // \f + token_escape_horizontal_tab, // \t + token_escape_vertical_tab, // \v + token_escape_bell, // \a + token_escape_control, // \c + + token_end_of_pattern +}; + +}}} // namespace boost::xpressive::regex_constants + +#endif diff --git a/boost/xpressive/detail/dynamic/parser_traits.hpp b/boost/xpressive/detail/dynamic/parser_traits.hpp new file mode 100644 index 0000000000..6c3e152cac --- /dev/null +++ b/boost/xpressive/detail/dynamic/parser_traits.hpp @@ -0,0 +1,474 @@ +/////////////////////////////////////////////////////////////////////////////// +// detail/dynamic/parser_traits.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_PARSER_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_PARSER_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <climits> +#include <boost/assert.hpp> +#include <boost/throw_exception.hpp> +#include <boost/xpressive/regex_error.hpp> +#include <boost/xpressive/regex_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/dynamic/matchable.hpp> +#include <boost/xpressive/detail/dynamic/parser_enum.hpp> +#include <boost/xpressive/detail/utility/literals.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> + +namespace boost { namespace xpressive +{ + +/////////////////////////////////////////////////////////////////////////////// +// compiler_traits +// this works for char and wchar_t. it must be specialized for anything else. +// +template<typename RegexTraits> +struct compiler_traits +{ + typedef RegexTraits regex_traits; + typedef typename regex_traits::char_type char_type; + typedef typename regex_traits::string_type string_type; + typedef typename regex_traits::locale_type locale_type; + + /////////////////////////////////////////////////////////////////////////////// + // constructor + explicit compiler_traits(RegexTraits const &traits = RegexTraits()) + : traits_(traits) + , flags_(regex_constants::ECMAScript) + , space_(lookup_classname(traits_, "space")) + , alnum_(lookup_classname(traits_, "alnum")) + { + } + + /////////////////////////////////////////////////////////////////////////////// + // flags + regex_constants::syntax_option_type flags() const + { + return this->flags_; + } + + /////////////////////////////////////////////////////////////////////////////// + // flags + void flags(regex_constants::syntax_option_type flags) + { + this->flags_ = flags; + } + + /////////////////////////////////////////////////////////////////////////////// + // traits + regex_traits &traits() + { + return this->traits_; + } + + regex_traits const &traits() const + { + return this->traits_; + } + + /////////////////////////////////////////////////////////////////////////////// + // imbue + locale_type imbue(locale_type const &loc) + { + locale_type oldloc = this->traits().imbue(loc); + this->space_ = lookup_classname(this->traits(), "space"); + this->alnum_ = lookup_classname(this->traits(), "alnum"); + return oldloc; + } + + /////////////////////////////////////////////////////////////////////////////// + // getloc + locale_type getloc() const + { + return this->traits().getloc(); + } + + /////////////////////////////////////////////////////////////////////////////// + // get_token + // get a token and advance the iterator + template<typename FwdIter> + regex_constants::compiler_token_type get_token(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + if(this->eat_ws_(begin, end) == end) + { + return regex_constants::token_end_of_pattern; + } + + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, '\\'): return this->get_escape_token(++begin, end); + case BOOST_XPR_CHAR_(char_type, '.'): ++begin; return token_any; + case BOOST_XPR_CHAR_(char_type, '^'): ++begin; return token_assert_begin_line; + case BOOST_XPR_CHAR_(char_type, '$'): ++begin; return token_assert_end_line; + case BOOST_XPR_CHAR_(char_type, '('): ++begin; return token_group_begin; + case BOOST_XPR_CHAR_(char_type, ')'): ++begin; return token_group_end; + case BOOST_XPR_CHAR_(char_type, '|'): ++begin; return token_alternate; + case BOOST_XPR_CHAR_(char_type, '['): ++begin; return token_charset_begin; + + case BOOST_XPR_CHAR_(char_type, '*'): + case BOOST_XPR_CHAR_(char_type, '+'): + case BOOST_XPR_CHAR_(char_type, '?'): + return token_invalid_quantifier; + + case BOOST_XPR_CHAR_(char_type, ']'): + case BOOST_XPR_CHAR_(char_type, '{'): + default: + return token_literal; + } + } + + /////////////////////////////////////////////////////////////////////////////// + // get_quant_spec + template<typename FwdIter> + bool get_quant_spec(FwdIter &begin, FwdIter end, detail::quant_spec &spec) + { + using namespace regex_constants; + FwdIter old_begin; + + if(this->eat_ws_(begin, end) == end) + { + return false; + } + + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, '*'): + spec.min_ = 0; + spec.max_ = (std::numeric_limits<unsigned int>::max)(); + break; + + case BOOST_XPR_CHAR_(char_type, '+'): + spec.min_ = 1; + spec.max_ = (std::numeric_limits<unsigned int>::max)(); + break; + + case BOOST_XPR_CHAR_(char_type, '?'): + spec.min_ = 0; + spec.max_ = 1; + break; + + case BOOST_XPR_CHAR_(char_type, '{'): + old_begin = this->eat_ws_(++begin, end); + spec.min_ = spec.max_ = detail::toi(begin, end, this->traits()); + BOOST_XPR_ENSURE_ + ( + begin != old_begin && begin != end, error_brace, "invalid quantifier" + ); + + if(*begin == BOOST_XPR_CHAR_(char_type, ',')) + { + old_begin = this->eat_ws_(++begin, end); + spec.max_ = detail::toi(begin, end, this->traits()); + BOOST_XPR_ENSURE_ + ( + begin != end && BOOST_XPR_CHAR_(char_type, '}') == *begin + , error_brace, "invalid quantifier" + ); + + if(begin == old_begin) + { + spec.max_ = (std::numeric_limits<unsigned int>::max)(); + } + else + { + BOOST_XPR_ENSURE_ + ( + spec.min_ <= spec.max_, error_badbrace, "invalid quantification range" + ); + } + } + else + { + BOOST_XPR_ENSURE_ + ( + BOOST_XPR_CHAR_(char_type, '}') == *begin, error_brace, "invalid quantifier" + ); + } + break; + + default: + return false; + } + + spec.greedy_ = true; + if(this->eat_ws_(++begin, end) != end && BOOST_XPR_CHAR_(char_type, '?') == *begin) + { + ++begin; + spec.greedy_ = false; + } + + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // get_group_type + template<typename FwdIter> + regex_constants::compiler_token_type get_group_type(FwdIter &begin, FwdIter end, string_type &name) + { + using namespace regex_constants; + if(this->eat_ws_(begin, end) != end && BOOST_XPR_CHAR_(char_type, '?') == *begin) + { + this->eat_ws_(++begin, end); + BOOST_XPR_ENSURE_(begin != end, error_paren, "incomplete extension"); + + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, ':'): ++begin; return token_no_mark; + case BOOST_XPR_CHAR_(char_type, '>'): ++begin; return token_independent_sub_expression; + case BOOST_XPR_CHAR_(char_type, '#'): ++begin; return token_comment; + case BOOST_XPR_CHAR_(char_type, '='): ++begin; return token_positive_lookahead; + case BOOST_XPR_CHAR_(char_type, '!'): ++begin; return token_negative_lookahead; + case BOOST_XPR_CHAR_(char_type, 'R'): ++begin; return token_recurse; + case BOOST_XPR_CHAR_(char_type, '$'): + this->get_name_(++begin, end, name); + BOOST_XPR_ENSURE_(begin != end, error_paren, "incomplete extension"); + if(BOOST_XPR_CHAR_(char_type, '=') == *begin) + { + ++begin; + return token_rule_assign; + } + return token_rule_ref; + + case BOOST_XPR_CHAR_(char_type, '<'): + this->eat_ws_(++begin, end); + BOOST_XPR_ENSURE_(begin != end, error_paren, "incomplete extension"); + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, '='): ++begin; return token_positive_lookbehind; + case BOOST_XPR_CHAR_(char_type, '!'): ++begin; return token_negative_lookbehind; + default: + BOOST_THROW_EXCEPTION(regex_error(error_badbrace, "unrecognized extension")); + } + + case BOOST_XPR_CHAR_(char_type, 'P'): + this->eat_ws_(++begin, end); + BOOST_XPR_ENSURE_(begin != end, error_paren, "incomplete extension"); + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, '<'): + this->get_name_(++begin, end, name); + BOOST_XPR_ENSURE_(begin != end && BOOST_XPR_CHAR_(char_type, '>') == *begin++, error_paren, "incomplete extension"); + return token_named_mark; + case BOOST_XPR_CHAR_(char_type, '='): + this->get_name_(++begin, end, name); + BOOST_XPR_ENSURE_(begin != end, error_paren, "incomplete extension"); + return token_named_mark_ref; + default: + BOOST_THROW_EXCEPTION(regex_error(error_badbrace, "unrecognized extension")); + } + + case BOOST_XPR_CHAR_(char_type, 'i'): + case BOOST_XPR_CHAR_(char_type, 'm'): + case BOOST_XPR_CHAR_(char_type, 's'): + case BOOST_XPR_CHAR_(char_type, 'x'): + case BOOST_XPR_CHAR_(char_type, '-'): + return this->parse_mods_(begin, end); + + default: + BOOST_THROW_EXCEPTION(regex_error(error_badbrace, "unrecognized extension")); + } + } + + return token_literal; + } + + ////////////////////////////////////////////////////////////////////////// + // get_charset_token + // NOTE: white-space is *never* ignored in a charset. + template<typename FwdIter> + regex_constants::compiler_token_type get_charset_token(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + BOOST_ASSERT(begin != end); + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, '^'): ++begin; return token_charset_invert; + case BOOST_XPR_CHAR_(char_type, '-'): ++begin; return token_charset_hyphen; + case BOOST_XPR_CHAR_(char_type, ']'): ++begin; return token_charset_end; + case BOOST_XPR_CHAR_(char_type, '['): + { + FwdIter next = begin; ++next; + if(next != end) + { + BOOST_XPR_ENSURE_( + *next != BOOST_XPR_CHAR_(char_type, '=') + , error_collate + , "equivalence classes are not yet supported" + ); + + BOOST_XPR_ENSURE_( + *next != BOOST_XPR_CHAR_(char_type, '.') + , error_collate + , "collation sequences are not yet supported" + ); + + if(*next == BOOST_XPR_CHAR_(char_type, ':')) + { + begin = ++next; + return token_posix_charset_begin; + } + } + } + break; + case BOOST_XPR_CHAR_(char_type, ':'): + { + FwdIter next = begin; ++next; + if(next != end && *next == BOOST_XPR_CHAR_(char_type, ']')) + { + begin = ++next; + return token_posix_charset_end; + } + } + break; + case BOOST_XPR_CHAR_(char_type, '\\'): + if(++begin != end) + { + switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, 'b'): ++begin; return token_charset_backspace; + default:; + } + } + return token_escape; + default:; + } + return token_literal; + } + + ////////////////////////////////////////////////////////////////////////// + // get_escape_token + template<typename FwdIter> + regex_constants::compiler_token_type get_escape_token(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + if(begin != end) + { + switch(*begin) + { + //case BOOST_XPR_CHAR_(char_type, 'a'): ++begin; return token_escape_bell; + //case BOOST_XPR_CHAR_(char_type, 'c'): ++begin; return token_escape_control; + //case BOOST_XPR_CHAR_(char_type, 'e'): ++begin; return token_escape_escape; + //case BOOST_XPR_CHAR_(char_type, 'f'): ++begin; return token_escape_formfeed; + //case BOOST_XPR_CHAR_(char_type, 'n'): ++begin; return token_escape_newline; + //case BOOST_XPR_CHAR_(char_type, 't'): ++begin; return token_escape_horizontal_tab; + //case BOOST_XPR_CHAR_(char_type, 'v'): ++begin; return token_escape_vertical_tab; + case BOOST_XPR_CHAR_(char_type, 'A'): ++begin; return token_assert_begin_sequence; + case BOOST_XPR_CHAR_(char_type, 'b'): ++begin; return token_assert_word_boundary; + case BOOST_XPR_CHAR_(char_type, 'B'): ++begin; return token_assert_not_word_boundary; + case BOOST_XPR_CHAR_(char_type, 'E'): ++begin; return token_quote_meta_end; + case BOOST_XPR_CHAR_(char_type, 'Q'): ++begin; return token_quote_meta_begin; + case BOOST_XPR_CHAR_(char_type, 'Z'): ++begin; return token_assert_end_sequence; + // Non-standard extension to ECMAScript syntax + case BOOST_XPR_CHAR_(char_type, '<'): ++begin; return token_assert_word_begin; + case BOOST_XPR_CHAR_(char_type, '>'): ++begin; return token_assert_word_end; + default:; // fall-through + } + } + + return token_escape; + } + +private: + + ////////////////////////////////////////////////////////////////////////// + // parse_mods_ + template<typename FwdIter> + regex_constants::compiler_token_type parse_mods_(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + bool set = true; + do switch(*begin) + { + case BOOST_XPR_CHAR_(char_type, 'i'): this->flag_(set, icase_); break; + case BOOST_XPR_CHAR_(char_type, 'm'): this->flag_(!set, single_line); break; + case BOOST_XPR_CHAR_(char_type, 's'): this->flag_(!set, not_dot_newline); break; + case BOOST_XPR_CHAR_(char_type, 'x'): this->flag_(set, ignore_white_space); break; + case BOOST_XPR_CHAR_(char_type, ':'): ++begin; // fall-through + case BOOST_XPR_CHAR_(char_type, ')'): return token_no_mark; + case BOOST_XPR_CHAR_(char_type, '-'): if(false == (set = !set)) break; // else fall-through + default: BOOST_THROW_EXCEPTION(regex_error(error_paren, "unknown pattern modifier")); + } + while(BOOST_XPR_ENSURE_(++begin != end, error_paren, "incomplete extension")); + // this return is technically unreachable, but this must + // be here to work around a bug in gcc 4.0 + return token_no_mark; + } + + /////////////////////////////////////////////////////////////////////////////// + // flag_ + void flag_(bool set, regex_constants::syntax_option_type flag) + { + this->flags_ = set ? (this->flags_ | flag) : (this->flags_ & ~flag); + } + + /////////////////////////////////////////////////////////////////////////// + // is_space_ + bool is_space_(char_type ch) const + { + return 0 != this->space_ && this->traits().isctype(ch, this->space_); + } + + /////////////////////////////////////////////////////////////////////////// + // is_alnum_ + bool is_alnum_(char_type ch) const + { + return 0 != this->alnum_ && this->traits().isctype(ch, this->alnum_); + } + + /////////////////////////////////////////////////////////////////////////// + // get_name_ + template<typename FwdIter> + void get_name_(FwdIter &begin, FwdIter end, string_type &name) + { + this->eat_ws_(begin, end); + for(name.clear(); begin != end && this->is_alnum_(*begin); ++begin) + { + name.push_back(*begin); + } + this->eat_ws_(begin, end); + BOOST_XPR_ENSURE_(!name.empty(), regex_constants::error_paren, "incomplete extension"); + } + + /////////////////////////////////////////////////////////////////////////////// + // eat_ws_ + template<typename FwdIter> + FwdIter &eat_ws_(FwdIter &begin, FwdIter end) + { + if(0 != (regex_constants::ignore_white_space & this->flags())) + { + while(end != begin && (BOOST_XPR_CHAR_(char_type, '#') == *begin || this->is_space_(*begin))) + { + if(BOOST_XPR_CHAR_(char_type, '#') == *begin++) + { + while(end != begin && BOOST_XPR_CHAR_(char_type, '\n') != *begin++) {} + } + else + { + for(; end != begin && this->is_space_(*begin); ++begin) {} + } + } + } + + return begin; + } + + regex_traits traits_; + regex_constants::syntax_option_type flags_; + typename regex_traits::char_class_type space_; + typename regex_traits::char_class_type alnum_; +}; + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/detail/dynamic/sequence.hpp b/boost/xpressive/detail/dynamic/sequence.hpp new file mode 100644 index 0000000000..f1670f683b --- /dev/null +++ b/boost/xpressive/detail/dynamic/sequence.hpp @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// sequence.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_SEQUENCE_HPP_EAN_04_10_2006 +#define BOOST_XPRESSIVE_DETAIL_DYNAMIC_SEQUENCE_HPP_EAN_04_10_2006 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/assert.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/xpressive/detail/utility/width.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// sequence +template<typename BidiIter> +struct sequence +{ + sequence() + : pure_(true) + , width_(0) + , quant_(quant_none) + , head_() + , tail_(0) + , alt_end_xpr_() + , alternates_(0) + { + } + + template<typename Matcher> + sequence(intrusive_ptr<dynamic_xpression<Matcher, BidiIter> > const &xpr) + : pure_(Matcher::pure) + , width_(xpr->Matcher::get_width()) + , quant_(static_cast<quant_enum>(Matcher::quant)) + , head_(xpr) + , tail_(&xpr->next_) + , alt_end_xpr_() + , alternates_(0) + { + } + + template<typename Traits> + sequence(intrusive_ptr<dynamic_xpression<alternate_matcher<alternates_vector<BidiIter>, Traits>, BidiIter> > const &xpr) + : pure_(true) + , width_(0) + , quant_(quant_none) + , head_(xpr) + , tail_(&xpr->next_) + , alt_end_xpr_() + , alternates_(&xpr->alternates_) + { + } + + bool empty() const + { + return !this->head_; + } + + sequence<BidiIter> &operator +=(sequence<BidiIter> const &that) + { + if(this->empty()) + { + *this = that; + } + else if(!that.empty()) + { + *this->tail_ = that.head_; + this->tail_ = that.tail_; + // keep track of sequence width and purity + this->width_ += that.width_; + this->pure_ = this->pure_ && that.pure_; + this->set_quant_(); + } + return *this; + } + + sequence<BidiIter> &operator |=(sequence<BidiIter> that) + { + BOOST_ASSERT(!this->empty()); + BOOST_ASSERT(0 != this->alternates_); + + // Keep track of width and purity + if(this->alternates_->empty()) + { + this->width_ = that.width_; + this->pure_ = that.pure_; + } + else + { + this->width_ |= that.width_; + this->pure_ = this->pure_ && that.pure_; + } + + // through the wonders of reference counting, all alternates_ can share an end_alternate + if(!this->alt_end_xpr_) + { + this->alt_end_xpr_ = new alt_end_xpr_type; + } + + // terminate each alternate with an alternate_end_matcher + that += sequence(this->alt_end_xpr_); + this->alternates_->push_back(that.head_); + this->set_quant_(); + return *this; + } + + void repeat(quant_spec const &spec) + { + this->xpr().matchable()->repeat(spec, *this); + } + + shared_matchable<BidiIter> const &xpr() const + { + return this->head_; + } + + detail::width width() const + { + return this->width_; + } + + bool pure() const + { + return this->pure_; + } + + quant_enum quant() const + { + return this->quant_; + } + +private: + typedef dynamic_xpression<alternate_end_matcher, BidiIter> alt_end_xpr_type; + + void set_quant_() + { + this->quant_ = (!is_unknown(this->width_) && this->pure_) + ? (!this->width_ ? quant_none : quant_fixed_width) + : quant_variable_width; + } + + bool pure_; + detail::width width_; + quant_enum quant_; + shared_matchable<BidiIter> head_; + shared_matchable<BidiIter> *tail_; + intrusive_ptr<alt_end_xpr_type> alt_end_xpr_; + alternates_vector<BidiIter> *alternates_; +}; + +template<typename BidiIter> +inline sequence<BidiIter> operator +(sequence<BidiIter> left, sequence<BidiIter> const &right) +{ + return left += right; +} + +template<typename BidiIter> +inline sequence<BidiIter> operator |(sequence<BidiIter> left, sequence<BidiIter> const &right) +{ + return left |= right; +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/static/compile.hpp b/boost/xpressive/detail/static/compile.hpp new file mode 100644 index 0000000000..bc8af05bf4 --- /dev/null +++ b/boost/xpressive/detail/static/compile.hpp @@ -0,0 +1,104 @@ +/////////////////////////////////////////////////////////////////////////////// +// compile.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_STATIC_COMPILE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_COMPILE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/proto/core.hpp> +#include <boost/xpressive/regex_traits.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/core/linker.hpp> +#include <boost/xpressive/detail/core/optimize.hpp> +#include <boost/xpressive/detail/core/adaptor.hpp> +#include <boost/xpressive/detail/core/matcher/end_matcher.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/xpressive/detail/static/visitor.hpp> +#include <boost/xpressive/detail/static/grammar.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // static_compile_impl2 + template<typename Xpr, typename BidiIter, typename Traits> + void static_compile_impl2(Xpr const &xpr, shared_ptr<regex_impl<BidiIter> > const &impl, Traits const &tr) + { + typedef typename iterator_value<BidiIter>::type char_type; + impl->tracking_clear(); + impl->traits_ = new traits_holder<Traits>(tr); + + // "compile" the regex and wrap it in an xpression_adaptor. + typedef xpression_visitor<BidiIter, mpl::false_, Traits> visitor_type; + visitor_type visitor(tr, impl); + intrusive_ptr<matchable_ex<BidiIter> const> adxpr = make_adaptor<matchable_ex<BidiIter> >( + typename Grammar<char_type>::template impl<Xpr const &, end_xpression, visitor_type &>()( + xpr + , end_xpression() + , visitor + ) + ); + + // Link and optimize the regex + common_compile(adxpr, *impl, visitor.traits()); + + // References changed, update dependencies. + impl->tracking_update(); + } + + /////////////////////////////////////////////////////////////////////////////// + // pattern for imbued regexes. + struct XpressiveLocaleModifier + : proto::binary_expr< + modifier_tag + , proto::terminal<locale_modifier<proto::_> > + , proto::_ + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // static_compile_impl1 + template<typename Xpr, typename BidiIter> + typename disable_if<proto::matches<Xpr, XpressiveLocaleModifier> >::type + static_compile_impl1(Xpr const &xpr, shared_ptr<regex_impl<BidiIter> > const &impl) + { + // use default traits + typedef typename iterator_value<BidiIter>::type char_type; + typedef typename default_regex_traits<char_type>::type traits_type; + traits_type tr; + static_compile_impl2(xpr, impl, tr); + } + + /////////////////////////////////////////////////////////////////////////////// + // static_compile_impl1 + template<typename Xpr, typename BidiIter> + typename enable_if<proto::matches<Xpr, XpressiveLocaleModifier> >::type + static_compile_impl1(Xpr const &xpr, shared_ptr<regex_impl<BidiIter> > const &impl) + { + // use specified traits + typedef typename proto::result_of::value<typename proto::result_of::left<Xpr>::type>::type::locale_type locale_type; + typedef typename regex_traits_type<locale_type, BidiIter>::type traits_type; + static_compile_impl2(proto::right(xpr), impl, traits_type(proto::value(proto::left(xpr)).getloc())); + } + + /////////////////////////////////////////////////////////////////////////////// + // static_compile + template<typename Xpr, typename BidiIter> + void static_compile(Xpr const &xpr, shared_ptr<regex_impl<BidiIter> > const &impl) + { + static_compile_impl1(xpr, impl); + } + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/static/grammar.hpp b/boost/xpressive/detail/static/grammar.hpp new file mode 100644 index 0000000000..82d1adc3c7 --- /dev/null +++ b/boost/xpressive/detail/static/grammar.hpp @@ -0,0 +1,365 @@ +/////////////////////////////////////////////////////////////////////////////// +// grammar.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_STATIC_GRAMMAR_HPP_EAN_11_12_2006 +#define BOOST_XPRESSIVE_DETAIL_STATIC_GRAMMAR_HPP_EAN_11_12_2006 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/if.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/proto/core.hpp> +#include <boost/xpressive/detail/static/is_pure.hpp> +#include <boost/xpressive/detail/static/transforms/as_matcher.hpp> +#include <boost/xpressive/detail/static/transforms/as_alternate.hpp> +#include <boost/xpressive/detail/static/transforms/as_sequence.hpp> +#include <boost/xpressive/detail/static/transforms/as_quantifier.hpp> +#include <boost/xpressive/detail/static/transforms/as_marker.hpp> +#include <boost/xpressive/detail/static/transforms/as_set.hpp> +#include <boost/xpressive/detail/static/transforms/as_independent.hpp> +#include <boost/xpressive/detail/static/transforms/as_modifier.hpp> +#include <boost/xpressive/detail/static/transforms/as_inverse.hpp> +#include <boost/xpressive/detail/static/transforms/as_action.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +#define BOOST_XPRESSIVE_CHECK_REGEX(Expr, Char)\ + BOOST_MPL_ASSERT\ + ((\ + typename boost::mpl::if_c<\ + boost::xpressive::is_valid_regex<Expr, Char>::value\ + , boost::mpl::true_\ + , boost::xpressive::INVALID_REGULAR_EXPRESSION\ + >::type\ + )); + +////////////////////////////////////////////////////////////////////////// +//**********************************************************************// +//* << NOTE! >> *// +//* *// +//* Whenever you change this grammar, you MUST also make corresponding *// +//* changes to width_of.hpp and is_pure.hpp. *// +//* *// +//**********************************************************************// +////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace xpressive +{ + template<typename Char> + struct Grammar; + + template<typename Char> + struct ActionableGrammar; + + namespace grammar_detail + { + /////////////////////////////////////////////////////////////////////////// + // CharLiteral + template<typename Char> + struct CharLiteral; + + /////////////////////////////////////////////////////////////////////////// + // ListSet + template<typename Char> + struct ListSet; + + /////////////////////////////////////////////////////////////////////////// + // as_repeat + template<typename Char, typename Gram, typename Greedy> + struct as_repeat + : if_< + make<detail::use_simple_repeat<_child, Char> > + , as_simple_quantifier<Gram, Greedy> + , as_default_quantifier<Greedy> + > + {}; + + /////////////////////////////////////////////////////////////////////////// + // NonGreedyRepeatCases + template<typename Gram> + struct NonGreedyRepeatCases + { + template<typename Tag, typename Dummy = void> + struct case_ + : not_<_> + {}; + + template<typename Dummy> + struct case_<tag::dereference, Dummy> + : dereference<Gram> + {}; + + template<typename Dummy> + struct case_<tag::unary_plus, Dummy> + : unary_plus<Gram> + {}; + + template<typename Dummy> + struct case_<tag::logical_not, Dummy> + : logical_not<Gram> + {}; + + template<uint_t Min, uint_t Max, typename Dummy> + struct case_<detail::generic_quant_tag<Min, Max>, Dummy> + : unary_expr<detail::generic_quant_tag<Min, Max>, Gram> + {}; + }; + + /////////////////////////////////////////////////////////////////////////// + // InvertibleCases + template<typename Char, typename Gram> + struct InvertibleCases + { + template<typename Tag, typename Dummy = void> + struct case_ + : not_<_> + {}; + + template<typename Dummy> + struct case_<tag::comma, Dummy> + : when<ListSet<Char>, as_list_set_matcher<Char> > + {}; + + template<typename Dummy> + struct case_<tag::assign, Dummy> + : when<ListSet<Char>, as_list_set_matcher<Char> > + {}; + + template<typename Dummy> + struct case_<tag::subscript, Dummy> + : when<subscript<detail::set_initializer_type, Gram>, call<as_set_matcher<Gram>(_right)> > + {}; + + template<typename Dummy> + struct case_<detail::lookahead_tag, Dummy> + : when< + unary_expr<detail::lookahead_tag, Gram> + , as_lookahead<Gram> + > + {}; + + template<typename Dummy> + struct case_<detail::lookbehind_tag, Dummy> + : when< + unary_expr<detail::lookbehind_tag, Gram> + , as_lookbehind<Gram> + > + {}; + + template<typename Dummy> + struct case_<tag::terminal, Dummy> + : when< + or_< + CharLiteral<Char> + , terminal<detail::posix_charset_placeholder> + , terminal<detail::range_placeholder<_> > + , terminal<detail::logical_newline_placeholder> + , terminal<detail::assert_word_placeholder<detail::word_boundary<mpl::true_> > > + > + , as_matcher + > + {}; + }; + + /////////////////////////////////////////////////////////////////////////// + // Cases + template<typename Char, typename Gram> + struct Cases + { + template<typename Tag, typename Dummy = void> + struct case_ + : not_<_> + {}; + + template<typename Dummy> + struct case_<tag::terminal, Dummy> + : when< + _ + , in_sequence<as_matcher> + > + {}; + + template<typename Dummy> + struct case_<tag::shift_right, Dummy> + : when< + shift_right<Gram, Gram> + , reverse_fold<_, _state, Gram> + > + {}; + + template<typename Dummy> + struct case_<tag::bitwise_or, Dummy> + : when< + bitwise_or<Gram, Gram> + , in_sequence< + as_alternate_matcher< + reverse_fold_tree<_, make<fusion::nil>, in_alternate_list<Gram> > + > + > + > + {}; + + template<typename Dummy, typename Greedy> + struct case_<optional_tag<Greedy> , Dummy> + : when< + unary_expr<optional_tag<Greedy>, Gram> + , in_sequence<call<as_optional<Gram, Greedy>(_child)> > + > + {}; + + template<typename Dummy> + struct case_<tag::dereference, Dummy> + : when< + dereference<Gram> + , call<Gram(as_repeat<Char, Gram, mpl::true_>)> + > + {}; + + template<typename Dummy> + struct case_<tag::unary_plus, Dummy> + : when< + unary_plus<Gram> + , call<Gram(as_repeat<Char, Gram, mpl::true_>)> + > + {}; + + template<typename Dummy> + struct case_<tag::logical_not, Dummy> + : when< + logical_not<Gram> + , call<Gram(as_repeat<Char, Gram, mpl::true_>)> + > + {}; + + template<uint_t Min, uint_t Max, typename Dummy> + struct case_<detail::generic_quant_tag<Min, Max>, Dummy> + : when< + unary_expr<detail::generic_quant_tag<Min, Max>, Gram> + , call<Gram(as_repeat<Char, Gram, mpl::true_>)> + > + {}; + + template<typename Dummy> + struct case_<tag::negate, Dummy> + : when< + negate<switch_<NonGreedyRepeatCases<Gram> > > + , call<Gram(call<as_repeat<Char, Gram, mpl::false_>(_child)>)> + > + {}; + + template<typename Dummy> + struct case_<tag::complement, Dummy> + : when< + complement<switch_<InvertibleCases<Char, Gram> > > + , in_sequence<call<as_inverse(call<switch_<InvertibleCases<Char, Gram> >(_child)>)> > + > + {}; + + template<typename Dummy> + struct case_<detail::modifier_tag, Dummy> + : when<binary_expr<detail::modifier_tag, _, Gram>, as_modifier<Gram> > + {}; + + template<typename Dummy> + struct case_<detail::lookahead_tag, Dummy> + : when< + unary_expr<detail::lookahead_tag, Gram> + , in_sequence<as_lookahead<Gram> > + > + {}; + + template<typename Dummy> + struct case_<detail::lookbehind_tag, Dummy> + : when< + unary_expr<detail::lookbehind_tag, Gram> + , in_sequence<as_lookbehind<Gram> > + > + {}; + + template<typename Dummy> + struct case_<detail::keeper_tag, Dummy> + : when< + unary_expr<detail::keeper_tag, Gram> + , in_sequence<as_keeper<Gram> > + > + {}; + + template<typename Dummy> + struct case_<tag::comma, Dummy> + : when<ListSet<Char>, in_sequence<as_list_set_matcher<Char> > > + {}; + + template<typename Dummy> + struct case_<tag::assign, Dummy> + : or_< + when<assign<detail::basic_mark_tag, Gram>, call<Gram(as_marker)> > + , when<ListSet<Char>, in_sequence<as_list_set_matcher<Char> > > + > + {}; + + template<typename Dummy> + struct case_<tag::subscript, Dummy> + : or_< + when<subscript<detail::set_initializer_type, Gram>, in_sequence<call<as_set_matcher<Gram>(_right)> > > + , when<subscript<ActionableGrammar<Char>, _>, call<ActionableGrammar<Char>(as_action)> > + > + {}; + }; + + /////////////////////////////////////////////////////////////////////////// + // ActionableCases + template<typename Char, typename Gram> + struct ActionableCases + { + template<typename Tag, typename Dummy = void> + struct case_ + : Cases<Char, Gram>::template case_<Tag> + {}; + + // Only in sub-expressions with actions attached do we allow attribute assignements + template<typename Dummy> + struct case_<proto::tag::assign, Dummy> + : or_< + typename Cases<Char, Gram>::template case_<proto::tag::assign> + , when<proto::assign<terminal<detail::attribute_placeholder<_> >, _>, in_sequence<as_attr_matcher> > + > + {}; + }; + + } // namespace detail + + /////////////////////////////////////////////////////////////////////////// + // Grammar + template<typename Char> + struct Grammar + : proto::switch_<grammar_detail::Cases<Char, Grammar<Char> > > + {}; + + template<typename Char> + struct ActionableGrammar + : proto::switch_<grammar_detail::ActionableCases<Char, ActionableGrammar<Char> > > + {}; + + /////////////////////////////////////////////////////////////////////////// + // INVALID_REGULAR_EXPRESSION + struct INVALID_REGULAR_EXPRESSION + : mpl::false_ + {}; + + /////////////////////////////////////////////////////////////////////////// + // is_valid_regex + template<typename Expr, typename Char> + struct is_valid_regex + : proto::matches<Expr, Grammar<Char> > + {}; + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/detail/static/is_pure.hpp b/boost/xpressive/detail/static/is_pure.hpp new file mode 100644 index 0000000000..f7da4f04bb --- /dev/null +++ b/boost/xpressive/detail/static/is_pure.hpp @@ -0,0 +1,216 @@ +/////////////////////////////////////////////////////////////////////////////// +// is_pure.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_STATIC_IS_PURE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_IS_PURE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/ref.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/mpl/not_equal_to.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/width_of.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // use_simple_repeat_terminal + // + template<typename Expr, typename Char, bool IsXpr = is_xpr<Expr>::value> + struct use_simple_repeat_terminal + : mpl::bool_< + Expr::quant == quant_fixed_width + || (Expr::width != unknown_width::value && Expr::pure) + > + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_terminal<Expr, Char, false> + : mpl::true_ // char literals, string literals, etc. + {}; + + template<typename BidiIter, typename Char> + struct use_simple_repeat_terminal<tracking_ptr<regex_impl<BidiIter> >, Char, false> + : mpl::false_ // basic_regex + {}; + + template<typename BidiIter, typename Char> + struct use_simple_repeat_terminal<reference_wrapper<basic_regex<BidiIter> >, Char, false> + : mpl::false_ // basic_regex + {}; + + template<typename BidiIter, typename Char> + struct use_simple_repeat_terminal<reference_wrapper<basic_regex<BidiIter> const>, Char, false> + : mpl::false_ // basic_regex + {}; + + /////////////////////////////////////////////////////////////////////////////// + // use_simple_repeat_ + // + template<typename Expr, typename Char, typename Tag = typename Expr::proto_tag> + struct use_simple_repeat_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::terminal> + : use_simple_repeat_terminal<typename proto::result_of::value<Expr>::type, Char> + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::shift_right> + : mpl::and_< + use_simple_repeat_<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + , use_simple_repeat_<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char> + > + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::bitwise_or> + : mpl::and_< + mpl::not_equal_to<unknown_width, width_of<Expr, Char> > + , use_simple_repeat_<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + , use_simple_repeat_<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char> + > + {}; + + template<typename Left> + struct use_simple_repeat_assign + {}; + + template<> + struct use_simple_repeat_assign<mark_placeholder> + : mpl::false_ + {}; + + template<> + struct use_simple_repeat_assign<set_initializer> + : mpl::true_ + {}; + + template<typename Nbr> + struct use_simple_repeat_assign<attribute_placeholder<Nbr> > + : mpl::false_ + {}; + + // either (s1 = ...) or (a1 = ...) or (set = ...) + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::assign> + : use_simple_repeat_assign< + typename proto::result_of::value< + typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr + >::type + > + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, modifier_tag> + : use_simple_repeat_<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char> + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, lookahead_tag> + : mpl::false_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, lookbehind_tag> + : mpl::false_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, keeper_tag> + : mpl::false_ + {}; + + // when complementing a set or an assertion, the purity is that of the set (true) or the assertion + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::complement> + : use_simple_repeat_<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + {}; + + // The comma is used in list-initialized sets, which are pure + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::comma> + : mpl::true_ + {}; + + // The subscript operator[] is used for sets, as in set['a' | range('b','h')] + // It is also used for actions, which by definition have side-effects and thus are impure + template<typename Expr, typename Char, typename Left> + struct use_simple_repeat_subscript + : mpl::false_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_subscript<Expr, Char, set_initializer_type> + : mpl::true_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::subscript> + : use_simple_repeat_subscript<Expr, Char, typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr> + {}; + + // Quantified expressions are variable-width and cannot use the simple quantifier + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::unary_plus> + : mpl::false_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::dereference> + : mpl::false_ + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::logical_not> + : mpl::false_ + {}; + + template<typename Expr, typename Char, uint_t Min, uint_t Max> + struct use_simple_repeat_<Expr, Char, generic_quant_tag<Min, Max> > + : mpl::false_ + {}; + + template<typename Expr, typename Char, uint_t Count> + struct use_simple_repeat_<Expr, Char, generic_quant_tag<Count, Count> > + : use_simple_repeat_<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + {}; + + template<typename Expr, typename Char> + struct use_simple_repeat_<Expr, Char, proto::tag::negate> + : use_simple_repeat_<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // use_simple_repeat + // + template<typename Expr, typename Char> + struct use_simple_repeat + : use_simple_repeat_<Expr, Char> + { + // should never try to repeat something of 0-width + BOOST_MPL_ASSERT_RELATION(0, !=, (width_of<Expr, Char>::value)); + }; + + template<typename Expr, typename Char> + struct use_simple_repeat<Expr &, Char> + : use_simple_repeat_<Expr, Char> + { + // should never try to repeat something of 0-width + BOOST_MPL_ASSERT_RELATION(0, !=, (width_of<Expr, Char>::value)); + }; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/static/modifier.hpp b/boost/xpressive/detail/static/modifier.hpp new file mode 100644 index 0000000000..82e4a76faf --- /dev/null +++ b/boost/xpressive/detail/static/modifier.hpp @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// modifier.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_STATIC_MODIFIER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_MODIFIER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4510) // default constructor could not be generated +# pragma warning(disable : 4610) // user defined constructor required +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/proto/traits.hpp> +#include <boost/xpressive/regex_constants.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // modifier + template<typename Modifier> + struct modifier_op + { + typedef regex_constants::syntax_option_type opt_type; + + template<typename Expr> + struct apply + { + typedef typename proto::binary_expr< + modifier_tag + , typename proto::terminal<Modifier>::type + , typename proto::result_of::as_child<Expr const>::type + >::type type; + }; + + template<typename Expr> + typename apply<Expr>::type const + operator ()(Expr const &expr) const + { + typename apply<Expr>::type that = {{this->mod_}, proto::as_child(expr)}; + return that; + } + + operator opt_type() const + { + return this->opt_; + } + + Modifier mod_; + opt_type opt_; + }; + +}}} + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/static/placeholders.hpp b/boost/xpressive/detail/static/placeholders.hpp new file mode 100644 index 0000000000..5c95538430 --- /dev/null +++ b/boost/xpressive/detail/static/placeholders.hpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////// +// placeholders.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_STATIC_PLACEHOLDERS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_PLACEHOLDERS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable:4510) // default constructor could not be generated +# pragma warning(disable:4610) // can never be instantiated - user defined constructor required +#endif + +#include <string> +#include <boost/shared_ptr.hpp> +#include <boost/xpressive/detail/core/quant_style.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// mark_placeholder +// +struct mark_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_variable_width, unknown_width::value, true) + + int mark_number_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// posix_charset_placeholder +// +struct posix_charset_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_fixed_width, 1, true) + + char const *name_; + bool not_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// assert_word_placeholder +// +template<typename Cond> +struct assert_word_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) +}; + +/////////////////////////////////////////////////////////////////////////////// +// range_placeholder +// +template<typename Char> +struct range_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_fixed_width, 1, true) + + Char ch_min_; + Char ch_max_; + bool not_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// assert_bol_placeholder +// +struct assert_bol_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) +}; + +/////////////////////////////////////////////////////////////////////////////// +// assert_eol_placeholder +// +struct assert_eol_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_none, 0, true) +}; + +/////////////////////////////////////////////////////////////////////////////// +// logical_newline_placeholder +// +struct logical_newline_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_variable_width, unknown_width::value, true) +}; + +/////////////////////////////////////////////////////////////////////////////// +// self_placeholder +// +struct self_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_variable_width, unknown_width::value, false) +}; + +/////////////////////////////////////////////////////////////////////////////// +// attribute_placeholder +// +template<typename Nbr> +struct attribute_placeholder +{ + BOOST_XPR_QUANT_STYLE(quant_variable_width, unknown_width::value, false) + + typedef Nbr nbr_type; + static Nbr nbr() { return Nbr(); } +}; + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/static/static.hpp b/boost/xpressive/detail/static/static.hpp new file mode 100644 index 0000000000..ed51b517aa --- /dev/null +++ b/boost/xpressive/detail/static/static.hpp @@ -0,0 +1,259 @@ +/////////////////////////////////////////////////////////////////////////////// +// static.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_STATIC_STATIC_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_STATIC_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/linker.hpp> +#include <boost/xpressive/detail/core/peeker.hpp> +#include <boost/xpressive/detail/static/placeholders.hpp> +#include <boost/xpressive/detail/utility/width.hpp> + +// Random thoughts: +// - must support indirect repeat counts {$n,$m} +// - add ws to eat whitespace (make *ws illegal) +// - a{n,m} -> repeat<n,m>(a) +// - a{$n,$m} -> repeat(n,m)(a) +// - add nil to match nothing +// - instead of s1, s2, etc., how about s[1], s[2], etc.? Needlessly verbose? + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// stacked_xpression +// +template<typename Top, typename Next> +struct stacked_xpression + : Next +{ + // match + // delegates to Next + template<typename BidiIter> + bool match(match_state<BidiIter> &state) const + { + return static_cast<Next const *>(this)-> + BOOST_NESTED_TEMPLATE push_match<Top>(state); + } + + // top_match + // jump back to the xpression on top of the xpression stack, + // and keep the xpression on the stack. + template<typename BidiIter> + static bool top_match(match_state<BidiIter> &state, void const *top) + { + return static_cast<Top const *>(top)-> + BOOST_NESTED_TEMPLATE push_match<Top>(state); + } + + // pop_match + // jump back to the xpression on top of the xpression stack, + // pop the xpression off the stack. + template<typename BidiIter> + static bool pop_match(match_state<BidiIter> &state, void const *top) + { + return static_cast<Top const *>(top)->match(state); + } + + // skip_match + // pop the xpression off the top of the stack and ignore it; call + // match on next. + template<typename BidiIter> + bool skip_match(match_state<BidiIter> &state) const + { + // could be static_xpression::skip_impl or stacked_xpression::skip_impl + // depending on if there is 1 or more than 1 xpression on the + // xpression stack + return Top::skip_impl(*static_cast<Next const *>(this), state); + } + +//protected: + + // skip_impl + // implementation of skip_match. + template<typename That, typename BidiIter> + static bool skip_impl(That const &that, match_state<BidiIter> &state) + { + return that.BOOST_NESTED_TEMPLATE push_match<Top>(state); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// stacked_xpression_cast +// +template<typename Top, typename Next> +inline stacked_xpression<Top, Next> const &stacked_xpression_cast(Next const &next) +{ + // NOTE: this is a little white lie. The "next" object doesn't really have + // the type to which we're casting it. It is harmless, though. We are only using + // the cast to decorate the next object with type information. It is done + // this way to save stack space. + BOOST_MPL_ASSERT_RELATION(sizeof(stacked_xpression<Top, Next>), ==, sizeof(Next)); + return *static_cast<stacked_xpression<Top, Next> const *>(&next); +} + +/////////////////////////////////////////////////////////////////////////////// +// static_xpression +// +template<typename Matcher, typename Next> +struct static_xpression + : Matcher +{ + Next next_; + + BOOST_STATIC_CONSTANT(bool, pure = Matcher::pure && Next::pure); + BOOST_STATIC_CONSTANT( + std::size_t + , width = + Matcher::width != unknown_width::value && Next::width != unknown_width::value + ? Matcher::width + Next::width + : unknown_width::value + ); + + static_xpression(Matcher const &matcher = Matcher(), Next const &next = Next()) + : Matcher(matcher) + , next_(next) + { + } + + // match + // delegates to the Matcher + template<typename BidiIter> + bool match(match_state<BidiIter> &state) const + { + return this->Matcher::match(state, this->next_); + } + + // push_match + // call match on this, but also push "Top" onto the xpression + // stack so we know what we are jumping back to later. + template<typename Top, typename BidiIter> + bool push_match(match_state<BidiIter> &state) const + { + return this->Matcher::match(state, stacked_xpression_cast<Top>(this->next_)); + } + + // skip_impl + // implementation of skip_match, called from stacked_xpression::skip_match + template<typename That, typename BidiIter> + static bool skip_impl(That const &that, match_state<BidiIter> &state) + { + return that.match(state); + } + + // for linking a compiled regular xpression + template<typename Char> + void link(xpression_linker<Char> &linker) const + { + linker.accept(*static_cast<Matcher const *>(this), &this->next_); + this->next_.link(linker); + } + + // for building a lead-follow + template<typename Char> + void peek(xpression_peeker<Char> &peeker) const + { + this->peek_next_(peeker.accept(*static_cast<Matcher const *>(this)), peeker); + } + + // for getting xpression width + detail::width get_width() const + { + return this->get_width_(mpl::size_t<width>()); + } + +private: + + static_xpression &operator =(static_xpression const &); + + template<typename Char> + void peek_next_(mpl::true_, xpression_peeker<Char> &peeker) const + { + this->next_.peek(peeker); + } + + template<typename Char> + void peek_next_(mpl::false_, xpression_peeker<Char> &) const + { + // no-op + } + + template<std::size_t Width> + detail::width get_width_(mpl::size_t<Width>) const + { + return Width; + } + + detail::width get_width_(unknown_width) const + { + // Should only be called in contexts where the width is + // known to be fixed. + return this->Matcher::get_width() + this->next_.get_width(); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// make_static +// +template<typename Matcher> +inline static_xpression<Matcher> const +make_static(Matcher const &matcher) +{ + return static_xpression<Matcher>(matcher); +} + +template<typename Matcher, typename Next> +inline static_xpression<Matcher, Next> const +make_static(Matcher const &matcher, Next const &next) +{ + return static_xpression<Matcher, Next>(matcher, next); +} + +/////////////////////////////////////////////////////////////////////////////// +// no_next +// +struct no_next +{ + BOOST_STATIC_CONSTANT(std::size_t, width = 0); + BOOST_STATIC_CONSTANT(bool, pure = true); + + template<typename Char> + void link(xpression_linker<Char> &) const + { + } + + template<typename Char> + void peek(xpression_peeker<Char> &peeker) const + { + peeker.fail(); + } + + detail::width get_width() const + { + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// get_mark_number +// +inline int get_mark_number(basic_mark_tag const &mark) +{ + return proto::value(mark).mark_number_; +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_action.hpp b/boost/xpressive/detail/static/transforms/as_action.hpp new file mode 100644 index 0000000000..4cda17bc23 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_action.hpp @@ -0,0 +1,322 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_action.hpp +// +// Copyright 2008 Eric Niebler. +// Copyright 2008 David Jenkins. +// +// 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_STATIC_TRANSFORMS_AS_ACTION_HPP_EAN_04_05_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_ACTION_HPP_EAN_04_05_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/sizeof.hpp> +#include <boost/mpl/min_max.hpp> +#include <boost/mpl/apply_wrap.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/matcher/attr_end_matcher.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/xpressive/detail/static/transforms/as_quantifier.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform/arg.hpp> +#include <boost/proto/transform/call.hpp> +#include <boost/proto/transform/make.hpp> +#include <boost/proto/transform/when.hpp> +#include <boost/proto/transform/fold.hpp> +#include <boost/proto/transform/fold_tree.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // read_attr + // Placeholder that knows the slot number of an attribute as well as the type + // of the object stored in it. + template<typename Nbr, typename Matcher> + struct read_attr + { + typedef Nbr nbr_type; + typedef Matcher matcher_type; + static Nbr nbr() { return Nbr(); } + }; + + template<typename Nbr, typename Matcher> + struct read_attr<Nbr, Matcher &> + { + typedef Nbr nbr_type; + typedef Matcher matcher_type; + }; + +}}} + +namespace boost { namespace xpressive { namespace grammar_detail +{ + /////////////////////////////////////////////////////////////////////////////// + // FindAttr + // Look for patterns like (a1= terminal<RHS>) and return the type of the RHS. + template<typename Nbr> + struct FindAttr + : or_< + // Ignore nested actions, because attributes are scoped + when< subscript<_, _>, _state > + , when< terminal<_>, _state > + , when< proto::assign<terminal<detail::attribute_placeholder<Nbr> >, _>, call<_value(_right)> > + , otherwise< fold<_, _state, FindAttr<Nbr> > > + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_read_attr + // For patterns like (a1 = RHS)[ref(i) = a1], transform to + // (a1 = RHS)[ref(i) = read_attr<1, RHS>] so that when reading the attribute + // we know what type is stored in the attribute slot. + struct as_read_attr : proto::transform<as_read_attr> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef + typename FindAttr<typename expr_type::proto_child0::nbr_type>::template impl< + State + , mpl::void_ + , int + >::result_type + attr_type; + + typedef + typename proto::terminal< + detail::read_attr< + typename expr_type::proto_child0::nbr_type + , BOOST_PROTO_UNCVREF(attr_type) + > + >::type + result_type; + + result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const + { + result_type that = {{}}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // DeepCopy + // Turn all refs into values, and also bind all attribute placeholders with + // the types from which they are being assigned. + struct DeepCopy + : or_< + when< terminal<detail::attribute_placeholder<_> >, as_read_attr> + , when< terminal<_>, proto::_deep_copy> + , otherwise< nary_expr<_, vararg<DeepCopy> > > + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // attr_nbr + // For an attribute placeholder, return the attribute's slot number. + struct attr_nbr : proto::transform<attr_nbr> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef typename expr_type::proto_child0::nbr_type::type result_type; + }; + }; + + struct max_attr; + + /////////////////////////////////////////////////////////////////////////////// + // MaxAttr + // In an action (rx)[act], find the largest attribute slot being used. + struct MaxAttr + : or_< + when< terminal<detail::attribute_placeholder<_> >, attr_nbr> + , when< terminal<_>, make<mpl::int_<0> > > + // Ignore nested actions, because attributes are scoped: + , when< subscript<_, _>, make<mpl::int_<0> > > + , otherwise< fold<_, make<mpl::int_<0> >, max_attr> > + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // max_attr + // Take the maximum of the current attr slot number and the state. + struct max_attr : proto::transform<max_attr> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename mpl::max< + typename impl::state + , typename MaxAttr::template impl<Expr, State, Data>::result_type + >::type + result_type; + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // as_attr_matcher + // turn a1=matcher into attr_matcher<Matcher>(1) + struct as_attr_matcher : proto::transform<as_attr_matcher> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef typename impl::data data_type; + typedef + detail::attr_matcher< + typename proto::result_of::value<typename expr_type::proto_child1>::type + , typename data_type::traits_type + , typename data_type::icase_type + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + return result_type( + proto::value(proto::left(expr)).nbr() + , proto::value(proto::right(expr)) + , data.traits() + ); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // add_attrs + // Wrap an expression in attr_begin_matcher/attr_end_matcher pair + struct add_attrs : proto::transform<add_attrs> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + detail::attr_begin_matcher< + typename MaxAttr::template impl<Expr, mpl::int_<0>, int>::result_type + > + begin_type; + + typedef typename impl::expr expr_type; + + typedef + typename shift_right< + typename terminal<begin_type>::type + , typename shift_right< + Expr + , terminal<detail::attr_end_matcher>::type + >::type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param + ) const + { + begin_type begin; + detail::attr_end_matcher end; + result_type that = {{begin}, {expr, {end}}}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // InsertAttrs + struct InsertAttrs + : if_<MaxAttr, add_attrs, _> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // CheckAssertion + struct CheckAssertion + : proto::function<terminal<detail::check_tag>, _> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // action_transform + // Turn A[B] into (mark_begin(n) >> A >> mark_end(n) >> action_matcher<B>(n)) + // If A and B use attributes, wrap the above expression in + // a attr_begin_matcher<Count> / attr_end_matcher pair, where Count is + // the number of attribute slots used by the pattern/action. + struct as_action : proto::transform<as_action> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename proto::result_of::left<Expr>::type expr_type; + typedef typename proto::result_of::right<Expr>::type action_type; + + typedef + typename DeepCopy::impl<action_type, expr_type, int>::result_type + action_copy_type; + + typedef + typename InsertMark::impl<expr_type, State, Data>::result_type + marked_expr_type; + + typedef + typename mpl::if_c< + proto::matches<action_type, CheckAssertion>::value + , detail::predicate_matcher<action_copy_type> + , detail::action_matcher<action_copy_type> + >::type + matcher_type; + + typedef + typename proto::shift_right< + marked_expr_type + , typename proto::terminal<matcher_type>::type + >::type + no_attr_type; + + typedef + typename InsertAttrs::impl<no_attr_type, State, Data>::result_type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + int dummy = 0; + marked_expr_type marked_expr = + InsertMark::impl<expr_type, State, Data>()(proto::left(expr), state, data); + + no_attr_type that = { + marked_expr + , { + matcher_type( + DeepCopy::impl<action_type, expr_type, int>()( + proto::right(expr) + , proto::left(expr) + , dummy + ) + , proto::value(proto::left(marked_expr)).mark_number_ + ) + } + }; + return InsertAttrs::impl<no_attr_type, State, Data>()(that, state, data); + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_alternate.hpp b/boost/xpressive/detail/static/transforms/as_alternate.hpp new file mode 100644 index 0000000000..521bb861e9 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_alternate.hpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_alternate.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_STATIC_TRANSFORMS_AS_ALTERNATE_HPP_EAN_04_01_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_ALTERNATE_HPP_EAN_04_01_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/proto/core.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/xpressive/detail/core/matcher/alternate_matcher.hpp> +#include <boost/xpressive/detail/utility/cons.hpp> + +namespace boost { namespace xpressive +{ + namespace detail + { + /////////////////////////////////////////////////////////////////////////////// + // alternates_list + // a fusion-compatible sequence of alternate expressions, that also keeps + // track of the list's width and purity. + template<typename Head, typename Tail> + struct alternates_list + : fusion::cons<Head, Tail> + { + BOOST_STATIC_CONSTANT(std::size_t, width = Head::width == Tail::width ? Head::width : detail::unknown_width::value); + BOOST_STATIC_CONSTANT(bool, pure = Head::pure && Tail::pure); + + alternates_list(Head const &head, Tail const &tail) + : fusion::cons<Head, Tail>(head, tail) + { + } + }; + + template<typename Head> + struct alternates_list<Head, fusion::nil> + : fusion::cons<Head, fusion::nil> + { + BOOST_STATIC_CONSTANT(std::size_t, width = Head::width); + BOOST_STATIC_CONSTANT(bool, pure = Head::pure); + + alternates_list(Head const &head, fusion::nil const &tail) + : fusion::cons<Head, fusion::nil>(head, tail) + { + } + }; + } + + namespace grammar_detail + { + /////////////////////////////////////////////////////////////////////////////// + // in_alternate_list + template<typename Grammar, typename Callable = proto::callable> + struct in_alternate_list : proto::transform<in_alternate_list<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + detail::alternates_list< + typename Grammar::template impl< + Expr + , detail::alternate_end_xpression + , Data + >::result_type + , State + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + return result_type( + typename Grammar::template impl<Expr, detail::alternate_end_xpression, Data>()( + expr + , detail::alternate_end_xpression() + , data + ) + , state + ); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // as_alternate_matcher + template<typename Grammar, typename Callable = proto::callable> + struct as_alternate_matcher : proto::transform<as_alternate_matcher<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::data data_type; + typedef + detail::alternate_matcher< + typename Grammar::template impl<Expr, State, Data>::result_type + , typename data_type::traits_type + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + return result_type( + typename Grammar::template impl<Expr, State, Data>()(expr, state, data) + ); + } + }; + }; + } + +}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_independent.hpp b/boost/xpressive/detail/static/transforms/as_independent.hpp new file mode 100644 index 0000000000..0001273575 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_independent.hpp @@ -0,0 +1,215 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_independent.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_STATIC_TRANSFORMS_AS_INDEPENDENT_HPP_EAN_04_05_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_INDEPENDENT_HPP_EAN_04_05_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/sizeof.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/proto/core.hpp> +#include <boost/proto/transform/arg.hpp> +#include <boost/proto/transform/when.hpp> +#include <boost/proto/transform/fold.hpp> +#include <boost/proto/transform/fold_tree.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + struct keeper_tag + {}; + + struct lookahead_tag + {}; + + struct lookbehind_tag + {}; +}}} + +namespace boost { namespace xpressive { namespace grammar_detail +{ + // A grammar that only accepts static regexes that + // don't have semantic actions. + struct NotHasAction + : proto::switch_<struct NotHasActionCases> + {}; + + struct NotHasActionCases + { + template<typename Tag, int Dummy = 0> + struct case_ + : proto::nary_expr<Tag, proto::vararg<NotHasAction> > + {}; + + template<int Dummy> + struct case_<proto::tag::terminal, Dummy> + : not_< or_< + proto::terminal<detail::tracking_ptr<detail::regex_impl<_> > >, + proto::terminal<reference_wrapper<_> > + > > + {}; + + template<int Dummy> + struct case_<proto::tag::comma, Dummy> + : proto::_ // because (set='a','b') can't contain an action + {}; + + template<int Dummy> + struct case_<proto::tag::complement, Dummy> + : proto::_ // because in ~X, X can't contain an unscoped action + {}; + + template<int Dummy> + struct case_<detail::lookahead_tag, Dummy> + : proto::_ // because actions in lookaheads are scoped + {}; + + template<int Dummy> + struct case_<detail::lookbehind_tag, Dummy> + : proto::_ // because actions in lookbehinds are scoped + {}; + + template<int Dummy> + struct case_<detail::keeper_tag, Dummy> + : proto::_ // because actions in keepers are scoped + {}; + + template<int Dummy> + struct case_<proto::tag::subscript, Dummy> + : proto::subscript<detail::set_initializer_type, _> + {}; // only accept set[...], not actions! + }; + + struct IndependentEndXpression + : or_< + when<NotHasAction, detail::true_xpression()> + , otherwise<detail::independent_end_xpression()> + > + {}; + + template<typename Grammar, typename Callable = proto::callable> + struct as_lookahead : proto::transform<as_lookahead<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename proto::result_of::child<Expr>::type arg_type; + + typedef + typename IndependentEndXpression::impl<arg_type, int, int>::result_type + end_xpr_type; + + typedef + typename Grammar::template impl<arg_type, end_xpr_type, Data>::result_type + xpr_type; + + typedef + detail::lookahead_matcher<xpr_type> + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + int i = 0; + return result_type( + typename Grammar::template impl<arg_type, end_xpr_type, Data>()( + proto::child(expr) + , IndependentEndXpression::impl<arg_type, int, int>()(proto::child(expr), i, i) + , data + ) + , false + ); + } + }; + }; + + template<typename Grammar, typename Callable = proto::callable> + struct as_lookbehind : proto::transform<as_lookbehind<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename proto::result_of::child<Expr>::type arg_type; + + typedef + typename IndependentEndXpression::impl<arg_type, int, int>::result_type + end_xpr_type; + + typedef + typename Grammar::template impl<arg_type, end_xpr_type, Data>::result_type + xpr_type; + + typedef + detail::lookbehind_matcher<xpr_type> + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + int i = 0; + xpr_type expr2 = typename Grammar::template impl<arg_type, end_xpr_type, Data>()( + proto::child(expr) + , IndependentEndXpression::impl<arg_type, int, int>()(proto::child(expr), i, i) + , data + ); + std::size_t width = expr2.get_width().value(); + return result_type(expr2, width, false); + } + }; + }; + + template<typename Grammar, typename Callable = proto::callable> + struct as_keeper : proto::transform<as_keeper<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename proto::result_of::child<Expr>::type arg_type; + + typedef + typename IndependentEndXpression::impl<arg_type, int, int>::result_type + end_xpr_type; + + typedef + typename Grammar::template impl<arg_type, end_xpr_type, Data>::result_type + xpr_type; + + typedef + detail::keeper_matcher<xpr_type> + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + int i = 0; + return result_type( + typename Grammar::template impl<arg_type, end_xpr_type, Data>()( + proto::child(expr) + , IndependentEndXpression::impl<arg_type, int, int>()(proto::child(expr), i, i) + , data + ) + ); + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_inverse.hpp b/boost/xpressive/detail/static/transforms/as_inverse.hpp new file mode 100644 index 0000000000..eef2d2e440 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_inverse.hpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_inverse.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_STATIC_TRANSFORMS_AS_INVERSE_HPP_EAN_04_05_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_INVERSE_HPP_EAN_04_05_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/sizeof.hpp> +#include <boost/mpl/not.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/proto/core.hpp> + +#define UNCV(x) typename remove_const<x>::type +#define UNREF(x) typename remove_reference<x>::type +#define UNCVREF(x) UNCV(UNREF(x)) + +namespace boost { namespace xpressive { namespace grammar_detail +{ + + template<typename T> + struct inverter + { + typedef T type; + static T call(T t) + { + t.inverse(); + return t; + } + }; + + template<typename Traits, typename ICase, typename Not> + struct inverter<detail::literal_matcher<Traits, ICase, Not> > + { + typedef detail::literal_matcher<Traits, ICase, typename mpl::not_<Not>::type> type; + static type call(detail::literal_matcher<Traits, ICase, Not> t) + { + return type(t.ch_); + } + }; + + template<typename Traits> + struct inverter<detail::logical_newline_matcher<Traits> > + { + // ~_ln matches any one character that is not in the "newline" character class + typedef detail::posix_charset_matcher<Traits> type; + static type call(detail::logical_newline_matcher<Traits> t) + { + return type(t.newline(), true); + } + }; + + template<typename Traits> + struct inverter<detail::assert_word_matcher<detail::word_boundary<mpl::true_>, Traits> > + { + typedef detail::assert_word_matcher<detail::word_boundary<mpl::false_>, Traits> type; + static type call(detail::assert_word_matcher<detail::word_boundary<mpl::true_>, Traits> t) + { + return type(t.word()); + } + }; + + struct as_inverse : proto::callable + { + template<typename Sig> + struct result; + + template<typename This, typename Matcher> + struct result<This(Matcher)> + : inverter<UNCVREF(Matcher)> + {}; + + template<typename Matcher> + typename inverter<Matcher>::type operator ()(Matcher const &matcher) const + { + return inverter<Matcher>::call(matcher); + } + }; + +}}} + +#undef UNCV +#undef UNREF +#undef UNCVREF + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_marker.hpp b/boost/xpressive/detail/static/transforms/as_marker.hpp new file mode 100644 index 0000000000..49ef8be124 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_marker.hpp @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_marker.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_STATIC_TRANSFORMS_AS_MARKER_HPP_EAN_04_01_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_MARKER_HPP_EAN_04_01_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/proto/core.hpp> + +namespace boost { namespace xpressive { namespace grammar_detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // as_marker + // Insert mark tags before and after the expression + struct as_marker : proto::transform<as_marker> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename shift_right< + terminal<detail::mark_begin_matcher>::type + , typename shift_right< + typename proto::result_of::right<typename impl::expr>::type + , terminal<detail::mark_end_matcher>::type + >::type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param + ) const + { + int mark_nbr = detail::get_mark_number(proto::left(expr)); + detail::mark_begin_matcher begin(mark_nbr); + detail::mark_end_matcher end(mark_nbr); + + result_type that = {{begin}, {proto::right(expr), {end}}}; + return that; + } + }; + }; +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_matcher.hpp b/boost/xpressive/detail/static/transforms/as_matcher.hpp new file mode 100644 index 0000000000..f8c6236196 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_matcher.hpp @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_matcher.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_STATIC_TRANSFORMS_AS_MATCHER_HPP_EAN_04_01_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_MATCHER_HPP_EAN_04_01_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> + +namespace boost { namespace xpressive { namespace grammar_detail +{ + struct as_matcher : proto::transform<as_matcher> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::data data_type; + + typedef + typename data_type::template apply< + typename proto::result_of::value<typename impl::expr>::type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + return data.call(proto::value(expr)); + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_modifier.hpp b/boost/xpressive/detail/static/transforms/as_modifier.hpp new file mode 100644 index 0000000000..6b1c587ab0 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_modifier.hpp @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_modifier.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_STATIC_TRANSFORMS_AS_MODIFIER_HPP_EAN_04_05_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_MODIFIER_HPP_EAN_04_05_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/sizeof.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/proto/core.hpp> + +#define UNCV(x) typename remove_const<x>::type +#define UNREF(x) typename remove_reference<x>::type +#define UNCVREF(x) UNCV(UNREF(x)) + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // regex operator tags + struct modifier_tag + {}; + +}}} + +namespace boost { namespace xpressive { namespace grammar_detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // as_modifier + template<typename Grammar, typename Callable = proto::callable> + struct as_modifier : proto::transform<as_modifier<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::result_of::value< + typename proto::result_of::left<typename impl::expr>::type + >::type + modifier_type; + + typedef + typename modifier_type::template apply<typename impl::data>::type + visitor_type; + + typedef + typename proto::result_of::right<Expr>::type + expr_type; + + typedef + typename Grammar::template impl<expr_type, State, visitor_type &>::result_type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + visitor_type new_visitor(proto::value(proto::left(expr)).call(data)); + return typename Grammar::template impl<expr_type, State, visitor_type &>()( + proto::right(expr) + , state + , new_visitor + ); + } + }; + }; + +}}} + +#undef UNCV +#undef UNREF +#undef UNCVREF + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_quantifier.hpp b/boost/xpressive/detail/static/transforms/as_quantifier.hpp new file mode 100644 index 0000000000..5770a8ed14 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_quantifier.hpp @@ -0,0 +1,378 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_quantifier.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_STATIC_TRANSFORMS_AS_QUANTIFIER_HPP_EAN_04_01_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_QUANTIFIER_HPP_EAN_04_01_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/proto/core.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // generic_quant_tag + template<uint_t Min, uint_t Max> + struct generic_quant_tag + { + typedef mpl::integral_c<uint_t, Min> min_type; + typedef mpl::integral_c<uint_t, Max> max_type; + }; +}}} + +namespace boost { namespace xpressive { namespace grammar_detail +{ + using detail::uint_t; + + /////////////////////////////////////////////////////////////////////////////// + // min_type / max_type + template<typename Tag> + struct min_type : Tag::min_type {}; + + template<> + struct min_type<proto::tag::unary_plus> : mpl::integral_c<uint_t, 1> {}; + + template<> + struct min_type<proto::tag::dereference> : mpl::integral_c<uint_t, 0> {}; + + template<> + struct min_type<proto::tag::logical_not> : mpl::integral_c<uint_t, 0> {}; + + template<typename Tag> + struct max_type : Tag::max_type {}; + + template<> + struct max_type<proto::tag::unary_plus> : mpl::integral_c<uint_t, UINT_MAX-1> {}; + + template<> + struct max_type<proto::tag::dereference> : mpl::integral_c<uint_t, UINT_MAX-1> {}; + + template<> + struct max_type<proto::tag::logical_not> : mpl::integral_c<uint_t, 1> {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_simple_quantifier + template<typename Grammar, typename Greedy, typename Callable = proto::callable> + struct as_simple_quantifier : proto::transform<as_simple_quantifier<Grammar, Greedy, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::result_of::child<Expr>::type + arg_type; + + typedef + typename Grammar::template impl<arg_type, detail::true_xpression, Data>::result_type + xpr_type; + + typedef + detail::simple_repeat_matcher<xpr_type, Greedy> + matcher_type; + + typedef + typename proto::terminal<matcher_type>::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + xpr_type xpr = typename Grammar::template impl<arg_type, detail::true_xpression, Data>()( + proto::child(expr) + , detail::true_xpression() + , data + ); + + typedef typename impl::expr expr_type; + matcher_type matcher( + xpr + , (uint_t)min_type<typename expr_type::proto_tag>::value + , (uint_t)max_type<typename expr_type::proto_tag>::value + , xpr.get_width().value() + ); + + return result_type::make(matcher); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // add_hidden_mark + struct add_hidden_mark : proto::transform<add_hidden_mark> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef + typename shift_right< + terminal<detail::mark_begin_matcher>::type + , typename shift_right< + Expr + , terminal<detail::mark_end_matcher>::type + >::type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + // we're inserting a hidden mark ... so grab the next hidden mark number. + int mark_nbr = data.get_hidden_mark(); + detail::mark_begin_matcher begin(mark_nbr); + detail::mark_end_matcher end(mark_nbr); + + result_type that = {{begin}, {expr, {end}}}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // InsertMark + struct InsertMark + : or_< + when<proto::assign<detail::basic_mark_tag, _>, _> + , otherwise<add_hidden_mark> + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_default_quantifier_impl + template<typename Greedy, uint_t Min, uint_t Max> + struct as_default_quantifier_impl : proto::transform<as_default_quantifier_impl<Greedy, Min, Max> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::result_of::child<Expr>::type + xpr_type; + + typedef + typename InsertMark::impl<xpr_type, State, Data>::result_type + marked_sub_type; + + typedef + typename shift_right< + terminal<detail::repeat_begin_matcher>::type + , typename shift_right< + marked_sub_type + , typename terminal<detail::repeat_end_matcher<Greedy> >::type + >::type + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + // Ensure this sub-expression is book-ended with mark matchers + marked_sub_type marked_sub = + InsertMark::impl<xpr_type, State, Data>()(proto::child(expr), state, data); + + // Get the mark_number from the begin_mark_matcher + int mark_number = proto::value(proto::left(marked_sub)).mark_number_; + BOOST_ASSERT(0 != mark_number); + + typedef typename impl::expr expr_type; + uint_t min_ = (uint_t)min_type<typename expr_type::proto_tag>(); + uint_t max_ = (uint_t)max_type<typename expr_type::proto_tag>(); + + detail::repeat_begin_matcher begin(mark_number); + detail::repeat_end_matcher<Greedy> end(mark_number, min_, max_); + + result_type that = {{begin}, {marked_sub, {end}}}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // optional_tag + template<typename Greedy> + struct optional_tag + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_default_optional + template<typename Grammar, typename Greedy, typename Callable = proto::callable> + struct as_default_optional : proto::transform<as_default_optional<Grammar, Greedy, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + detail::alternate_end_xpression + end_xpr; + + typedef + detail::optional_matcher< + typename Grammar::template impl<Expr, end_xpr, Data>::result_type + , Greedy + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + return result_type( + typename Grammar::template impl<Expr, end_xpr, Data>()(expr, end_xpr(), data) + ); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // as_mark_optional + template<typename Grammar, typename Greedy, typename Callable = proto::callable> + struct as_mark_optional : proto::transform<as_mark_optional<Grammar, Greedy, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + detail::alternate_end_xpression + end_xpr; + + typedef + detail::optional_mark_matcher< + typename Grammar::template impl<Expr, end_xpr, Data>::result_type + , Greedy + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + int mark_number = proto::value(proto::left(expr)).mark_number_; + + return result_type( + typename Grammar::template impl<Expr, end_xpr, Data>()(expr, end_xpr(), data) + , mark_number + ); + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // IsMarkerOrRepeater + struct IsMarkerOrRepeater + : or_< + shift_right<terminal<detail::repeat_begin_matcher>, _> + , assign<terminal<detail::mark_placeholder>, _> + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_optional + template<typename Grammar, typename Greedy> + struct as_optional + : or_< + when<IsMarkerOrRepeater, as_mark_optional<Grammar, Greedy> > + , otherwise<as_default_optional<Grammar, Greedy> > + > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // make_optional_ + template<typename Greedy, typename Callable = proto::callable> + struct make_optional_ : proto::transform<make_optional_<Greedy, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef + typename unary_expr< + optional_tag<Greedy> + , Expr + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param + ) const + { + result_type that = {expr}; + return that; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // as_default_quantifier_impl + template<typename Greedy, uint_t Max> + struct as_default_quantifier_impl<Greedy, 0, Max> + : call<make_optional_<Greedy>(as_default_quantifier_impl<Greedy, 1, Max>)> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_default_quantifier_impl + template<typename Greedy> + struct as_default_quantifier_impl<Greedy, 0, 1> + : call<make_optional_<Greedy>(_child)> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // as_default_quantifier + template<typename Greedy, typename Callable = proto::callable> + struct as_default_quantifier : proto::transform<as_default_quantifier<Greedy, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::expr expr_type; + typedef + as_default_quantifier_impl< + Greedy + , min_type<typename expr_type::proto_tag>::value + , max_type<typename expr_type::proto_tag>::value + > + other; + + typedef + typename other::template impl<Expr, State, Data>::result_type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + return typename other::template impl<Expr, State, Data>()(expr, state, data); + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_sequence.hpp b/boost/xpressive/detail/static/transforms/as_sequence.hpp new file mode 100644 index 0000000000..62301618f1 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_sequence.hpp @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_sequence.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_STATIC_TRANSFORMS_AS_SEQUENCE_HPP_EAN_04_01_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_SEQUENCE_HPP_EAN_04_01_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> + +namespace boost { namespace xpressive { namespace grammar_detail +{ + template<typename Grammar, typename Callable = proto::callable> + struct in_sequence : proto::transform<in_sequence<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + detail::static_xpression< + typename Grammar::template impl<Expr, State, Data>::result_type + , State + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param data + ) const + { + return result_type( + typename Grammar::template impl<Expr, State, Data>()(expr, state, data) + , state + ); + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transforms/as_set.hpp b/boost/xpressive/detail/static/transforms/as_set.hpp new file mode 100644 index 0000000000..6d5c252610 --- /dev/null +++ b/boost/xpressive/detail/static/transforms/as_set.hpp @@ -0,0 +1,224 @@ +/////////////////////////////////////////////////////////////////////////////// +// as_set.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_STATIC_TRANSFORMS_AS_SET_HPP_EAN_04_05_2007 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_SET_HPP_EAN_04_05_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/assert.hpp> +#include <boost/proto/core.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/static/static.hpp> +#include <boost/xpressive/detail/utility/chset/chset.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace grammar_detail +{ + + /////////////////////////////////////////////////////////////////////////// + // CharLiteral + template<typename Char> + struct CharLiteral + : or_< + terminal<char> + , terminal<Char> + > + {}; + + template<> + struct CharLiteral<char> + : terminal<char> + {}; + + /////////////////////////////////////////////////////////////////////////// + // ListSet + // matches expressions like (set= 'a','b','c') + // calculates the size of the set + template<typename Char> + struct ListSet + : or_< + when< + comma<ListSet<Char>, CharLiteral<Char> > + , make<mpl::next<call<ListSet<Char>(_left)> > > // TODO make a custom transform for this... + > + , when< + assign<detail::set_initializer_type, CharLiteral<Char> > + , make<mpl::int_<1> > + > + > + {}; + + template<typename Char, typename Traits> + void fill_list_set(Char *&, detail::set_initializer_type, Traits const &) + {} + + template<typename Char, typename Expr, typename Traits> + void fill_list_set(Char *&buffer, Expr const &expr, Traits const &traits) + { + fill_list_set(buffer, proto::left(expr), traits); + *buffer++ = traits.translate(detail::char_cast<Char>(proto::value(proto::right(expr)), traits)); + } + + /////////////////////////////////////////////////////////////////////////////// + // as_list_set_matcher + template<typename Char, typename Callable = proto::callable> + struct as_list_set_matcher : proto::transform<as_list_set_matcher<Char, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::data data_type; + typedef + detail::set_matcher< + typename data_type::traits_type + , typename ListSet<Char>::template impl<Expr, State, Data>::result_type + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + result_type set; + typedef typename impl::data data_type; + typename data_type::char_type *buffer = set.set_; + fill_list_set(buffer, expr, data.traits()); + return set; + } + }; + }; + + /////////////////////////////////////////////////////////////////////////////// + // merge_charset + // + template<typename Grammar, typename CharSet, typename Data> + struct merge_charset + { + typedef typename Data::traits_type traits_type; + typedef typename CharSet::char_type char_type; + typedef typename CharSet::icase_type icase_type; + + merge_charset(CharSet &charset, Data &data) + : charset_(charset) + , visitor_(data) + {} + + template<typename Expr> + void operator ()(Expr const &expr) const + { + this->call_(expr, typename Expr::proto_tag()); + } + + private: + merge_charset &operator =(merge_charset const &); + + template<typename Expr, typename Tag> + void call_(Expr const &expr, Tag) const + { + this->set_( + typename Grammar::template impl<Expr const &, detail::end_xpression, Data &>()( + expr + , detail::end_xpression() + , this->visitor_ + ) + ); + } + + template<typename Expr> + void call_(Expr const &expr, tag::bitwise_or) const + { + (*this)(proto::left(expr)); + (*this)(proto::right(expr)); + } + + template<typename Not> + void set_(detail::literal_matcher<traits_type, icase_type, Not> const &ch) const + { + // BUGBUG fixme! + BOOST_MPL_ASSERT_NOT((Not)); + set_char(this->charset_.charset_, ch.ch_, this->visitor_.traits(), icase_type()); + } + + void set_(detail::range_matcher<traits_type, icase_type> const &rg) const + { + // BUGBUG fixme! + BOOST_ASSERT(!rg.not_); + set_range(this->charset_.charset_, rg.ch_min_, rg.ch_max_, this->visitor_.traits(), icase_type()); + } + + template<typename Size> + void set_(detail::set_matcher<traits_type, Size> const &set_) const + { + // BUGBUG fixme! + BOOST_ASSERT(!set_.not_); + for(int i = 0; i < Size::value; ++i) + { + set_char(this->charset_.charset_, set_.set_[i], this->visitor_.traits(), icase_type()); + } + } + + void set_(detail::posix_charset_matcher<traits_type> const &posix) const + { + set_class(this->charset_.charset_, posix.mask_, posix.not_, this->visitor_.traits()); + } + + CharSet &charset_; + Data &visitor_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // + template<typename Grammar, typename Callable = proto::callable> + struct as_set_matcher : proto::transform<as_set_matcher<Grammar, Callable> > + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef typename impl::data data_type; + typedef typename data_type::char_type char_type; + + // if sizeof(char_type)==1, merge everything into a basic_chset + // BUGBUG this is not optimal. + typedef + typename mpl::if_c< + detail::is_narrow_char<char_type>::value + , detail::basic_chset<char_type> + , detail::compound_charset<typename data_type::traits_type> + >::type + charset_type; + + typedef + detail::charset_matcher< + typename data_type::traits_type + , typename data_type::icase_type + , charset_type + > + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param + , typename impl::data_param data + ) const + { + result_type matcher; + merge_charset<Grammar, result_type, typename impl::data> merge(matcher, data); + merge(expr); // Walks the tree and fills in the charset + return matcher; + } + }; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/transmogrify.hpp b/boost/xpressive/detail/static/transmogrify.hpp new file mode 100644 index 0000000000..67f6588c22 --- /dev/null +++ b/boost/xpressive/detail/static/transmogrify.hpp @@ -0,0 +1,240 @@ +/////////////////////////////////////////////////////////////////////////////// +// transmogrify.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_STATIC_TRANSMOGRIFY_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSMOGRIFY_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <cstring> // for std::strlen +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/matchers.hpp> +#include <boost/xpressive/detail/static/placeholders.hpp> +#include <boost/xpressive/detail/utility/dont_care.hpp> +#include <boost/xpressive/detail/utility/traits_utils.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + template<typename T, typename Char> + struct is_char_literal + : mpl::or_<is_same<T, Char>, is_same<T, char> > + {}; + + /////////////////////////////////////////////////////////////////////////////// + // transmogrify + // + template<typename BidiIter, typename ICase, typename Traits, typename Matcher, typename EnableIf = void> + struct default_transmogrify + { + typedef typename Traits::char_type char_type; + typedef typename Traits::string_type string_type; + + typedef typename mpl::if_c + < + is_char_literal<Matcher, char_type>::value + , literal_matcher<Traits, ICase, mpl::false_> + , string_matcher<Traits, ICase> + >::type type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2 const &m, Visitor &visitor) + { + return default_transmogrify::call_(m, visitor, is_char_literal<Matcher2, char_type>()); + } + + template<typename Matcher2, typename Visitor> + static type call_(Matcher2 const &m, Visitor &visitor, mpl::true_) + { + char_type ch = char_cast<char_type>(m, visitor.traits()); + return type(ch, visitor.traits()); + } + + template<typename Matcher2, typename Visitor> + static type call_(Matcher2 const &m, Visitor &visitor, mpl::false_) + { + string_type str = string_cast<string_type>(m, visitor.traits()); + return type(str, visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits, typename Matcher> + struct default_transmogrify<BidiIter, ICase, Traits, Matcher, typename Matcher::is_boost_xpressive_xpression_> + { + typedef Matcher type; + + template<typename Matcher2> + static Matcher2 const &call(Matcher2 const &m, dont_care) + { + return m; + } + }; + + template<typename BidiIter, typename ICase, typename Traits, typename Matcher> + struct transmogrify + : default_transmogrify<BidiIter, ICase, Traits, Matcher> + {}; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, assert_bol_placeholder > + { + typedef assert_bol_matcher<Traits> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2, Visitor &visitor) + { + return type(visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, assert_eol_placeholder > + { + typedef assert_eol_matcher<Traits> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2, Visitor &visitor) + { + return type(visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, logical_newline_placeholder > + { + typedef logical_newline_matcher<Traits> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2, Visitor &visitor) + { + return type(visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits, typename Char> + struct transmogrify<BidiIter, ICase, Traits, range_placeholder<Char> > + { + // By design, we don't widen character ranges. + typedef typename iterator_value<BidiIter>::type char_type; + BOOST_MPL_ASSERT((is_same<Char, char_type>)); + typedef range_matcher<Traits, ICase> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2 const &m, Visitor &visitor) + { + return type(m.ch_min_, m.ch_max_, m.not_, visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, mark_placeholder > + { + typedef mark_matcher<Traits, ICase> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2 const &m, Visitor &visitor) + { + return type(m.mark_number_, visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, posix_charset_placeholder > + { + typedef posix_charset_matcher<Traits> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2 const &m, Visitor &visitor) + { + char const *name_end = m.name_ + std::strlen(m.name_); + return type(visitor.traits().lookup_classname(m.name_, name_end, ICase::value), m.not_); + } + }; + + template<typename BidiIter, typename Traits, typename Size> + struct transmogrify<BidiIter, mpl::true_, Traits, set_matcher<Traits, Size> > + { + typedef set_matcher<Traits, Size> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2 m, Visitor &visitor) + { + m.nocase(visitor.traits()); + return m; + } + }; + + template<typename BidiIter, typename ICase, typename Traits, typename Cond> + struct transmogrify<BidiIter, ICase, Traits, assert_word_placeholder<Cond> > + { + typedef assert_word_matcher<Cond, Traits> type; + + template<typename Visitor> + static type call(dont_care, Visitor &visitor) + { + return type(visitor.traits()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, reference_wrapper<basic_regex<BidiIter> > > + { + typedef regex_byref_matcher<BidiIter> type; + + template<typename Matcher2> + static type call(Matcher2 const &m, dont_care) + { + return type(detail::core_access<BidiIter>::get_regex_impl(m.get())); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, reference_wrapper<basic_regex<BidiIter> const> > + { + typedef regex_byref_matcher<BidiIter> type; + + template<typename Matcher2> + static type call(Matcher2 const &m, dont_care) + { + return type(detail::core_access<BidiIter>::get_regex_impl(m.get())); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, tracking_ptr<regex_impl<BidiIter> > > + { + typedef regex_matcher<BidiIter> type; + + template<typename Matcher2> + static type call(Matcher2 const &m, dont_care) + { + return type(m.get()); + } + }; + + template<typename BidiIter, typename ICase, typename Traits> + struct transmogrify<BidiIter, ICase, Traits, self_placeholder > + { + typedef regex_byref_matcher<BidiIter> type; + + template<typename Matcher2, typename Visitor> + static type call(Matcher2, Visitor &visitor) + { + return type(visitor.self()); + } + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/type_traits.hpp b/boost/xpressive/detail/static/type_traits.hpp new file mode 100644 index 0000000000..67ba77e328 --- /dev/null +++ b/boost/xpressive/detail/static/type_traits.hpp @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////// +// type_traits.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_STATIC_TYPE_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_TYPE_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/bool.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// is_static_xpression +// +template<typename T> +struct is_static_xpression + : mpl::false_ +{ +}; + +template<typename Matcher, typename Next> +struct is_static_xpression<static_xpression<Matcher, Next> > + : mpl::true_ +{ +}; + +template<typename Top, typename Next> +struct is_static_xpression<stacked_xpression<Top, Next> > + : mpl::true_ +{ +}; + +////////////////////////////////////////////////////////////////////////// +// is_random +// +template<typename BidiIter> +struct is_random + : is_convertible + < + typename iterator_category<BidiIter>::type + , std::random_access_iterator_tag + > +{ +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/static/visitor.hpp b/boost/xpressive/detail/static/visitor.hpp new file mode 100644 index 0000000000..5a0213f695 --- /dev/null +++ b/boost/xpressive/detail/static/visitor.hpp @@ -0,0 +1,143 @@ +/////////////////////////////////////////////////////////////////////////////// +// visitor.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_STATIC_VISITOR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_VISITOR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/ref.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/static/transmogrify.hpp> +#include <boost/xpressive/detail/core/matcher/mark_begin_matcher.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // + template<typename BidiIter> + struct xpression_visitor_base + { + explicit xpression_visitor_base(shared_ptr<regex_impl<BidiIter> > const &self) + : self_(self) + { + } + + void swap(xpression_visitor_base<BidiIter> &that) + { + this->self_.swap(that.self_); + } + + int get_hidden_mark() + { + return -(int)(++this->self_->hidden_mark_count_); + } + + void mark_number(int mark_nbr) + { + if(0 < mark_nbr) + { + this->self_->mark_count_ = + (std::max)(this->self_->mark_count_, (std::size_t)mark_nbr); + } + } + + shared_ptr<regex_impl<BidiIter> > &self() + { + return this->self_; + } + + protected: + + template<typename Matcher> + void visit_(Matcher const &) + { + } + + void visit_(reference_wrapper<basic_regex<BidiIter> > const &rex) + { + // when visiting an embedded regex, track the references + this->self_->track_reference(*detail::core_access<BidiIter>::get_regex_impl(rex.get())); + } + + void visit_(reference_wrapper<basic_regex<BidiIter> const> const &rex) + { + // when visiting an embedded regex, track the references + this->self_->track_reference(*detail::core_access<BidiIter>::get_regex_impl(rex.get())); + } + + void visit_(tracking_ptr<regex_impl<BidiIter> > const &rex) + { + // when visiting an embedded regex, track the references + this->self_->track_reference(*rex.get()); + } + + void visit_(mark_placeholder const &backref) + { + // keep track of the largest mark number found + this->mark_number(backref.mark_number_); + } + + void visit_(mark_begin_matcher const &mark_begin) + { + // keep track of the largest mark number found + this->mark_number(mark_begin.mark_number_); + } + + private: + shared_ptr<regex_impl<BidiIter> > self_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // + template<typename BidiIter, typename ICase, typename Traits> + struct xpression_visitor + : xpression_visitor_base<BidiIter> + { + typedef BidiIter iterator_type; + typedef ICase icase_type; + typedef Traits traits_type; + typedef typename boost::iterator_value<BidiIter>::type char_type; + + explicit xpression_visitor(Traits const &tr, shared_ptr<regex_impl<BidiIter> > const &self) + : xpression_visitor_base<BidiIter>(self) + , traits_(tr) + { + } + + template<typename Matcher> + struct apply + { + typedef typename transmogrify<BidiIter, ICase, Traits, Matcher>::type type; + }; + + template<typename Matcher> + typename apply<Matcher>::type + call(Matcher const &matcher) + { + this->visit_(matcher); + return transmogrify<BidiIter, ICase, Traits, Matcher>::call(matcher, *this); + } + + Traits const &traits() const + { + return this->traits_; + } + + private: + + Traits traits_; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/static/width_of.hpp b/boost/xpressive/detail/static/width_of.hpp new file mode 100644 index 0000000000..eec6e5491d --- /dev/null +++ b/boost/xpressive/detail/static/width_of.hpp @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// width_of.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_STATIC_WIDTH_OF_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_STATIC_WIDTH_OF_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/ref.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/plus.hpp> +#include <boost/mpl/times.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/mpl/size_t.hpp> +#include <boost/mpl/equal_to.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/proto/traits.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + template<typename Expr, typename Char, typename Tag = typename Expr::proto_tag> + struct width_of; + + /////////////////////////////////////////////////////////////////////////////// + // add_widths + // + template<std::size_t N, std::size_t M> + struct add_widths + : mpl::size_t<N + M> + {}; + + template<std::size_t M> + struct add_widths<unknown_width::value, M> + : unknown_width + {}; + + template<std::size_t N> + struct add_widths<N, unknown_width::value> + : unknown_width + {}; + + template<> + struct add_widths<unknown_width::value, unknown_width::value> + : unknown_width + {}; + + /////////////////////////////////////////////////////////////////////////////// + // or_widths + // + template<std::size_t N, std::size_t M> + struct or_widths + : unknown_width + {}; + + template<std::size_t N> + struct or_widths<N, N> + : mpl::size_t<N> + {}; + + /////////////////////////////////////////////////////////////////////////////// + // is_char + // + template<typename T> + struct is_char + : mpl::false_ + {}; + + template<> + struct is_char<char> + : mpl::true_ + {}; + + template<> + struct is_char<wchar_t> + : mpl::true_ + {}; + + /////////////////////////////////////////////////////////////////////////////// + // width_of_terminal + // + template<typename Expr, typename Char, bool IsXpr = is_xpr<Expr>::value> + struct width_of_terminal + : mpl::size_t<Expr::width> // xpressive literals + {}; + + template<typename Expr, typename Char> + struct width_of_terminal<Expr, Char, false> + : unknown_width // unknown literals (eg, basic_string, basic_regex, etc.) + {}; + + template<typename Char> + struct width_of_terminal<Char, Char, false> + : mpl::size_t<1> // char literals + {}; + + template<typename Char> + struct width_of_terminal<char, Char, false> + : mpl::size_t<1> // char literals + {}; + + template<> + struct width_of_terminal<char, char, false> + : mpl::size_t<1> // char literals + {}; + + template<typename Elem, std::size_t N, typename Char> + struct width_of_terminal<Elem (&) [N], Char, false> + : mpl::size_t<N-is_char<Elem>::value> // string literals + {}; + + template<typename Elem, std::size_t N, typename Char> + struct width_of_terminal<Elem const (&) [N], Char, false> + : mpl::size_t<N-is_char<Elem>::value> // string literals + {}; + + /////////////////////////////////////////////////////////////////////////////// + // width_of + // + template<typename Expr, typename Char, typename Tag> + struct width_of + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::terminal> + : width_of_terminal<typename proto::result_of::value<Expr>::type, Char> + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::shift_right> + : add_widths< + width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>::value + , width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value + > + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::bitwise_or> + : or_widths< + width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>::value + , width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value + > + {}; + + template<typename Expr, typename Char, typename Left> + struct width_of_assign + {}; + + template<typename Expr, typename Char> + struct width_of_assign<Expr, Char, mark_placeholder> + : width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char> + {}; + + template<typename Expr, typename Char> + struct width_of_assign<Expr, Char, set_initializer> + : mpl::size_t<1> + {}; + + template<typename Expr, typename Char, typename Nbr> + struct width_of_assign<Expr, Char, attribute_placeholder<Nbr> > + : unknown_width + {}; + + // either (s1 = ...) or (a1 = ...) or (set = ...) + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::assign> + : width_of_assign< + Expr + , Char + , typename proto::result_of::value< + typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr + >::type + > + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, modifier_tag> + : width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char> + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, lookahead_tag> + : mpl::size_t<0> + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, lookbehind_tag> + : mpl::size_t<0> + {}; + + // keep() is used to turn off backtracking, so they should only be used + // for things that are variable-width (eg. quantified) + template<typename Expr, typename Char> + struct width_of<Expr, Char, keeper_tag> + : unknown_width + { + // TODO: keep() now has a second meaning: execute actions immediately. + // In that sense, it is perfectly reasonable to put a fixed-width + // sub-expression in a keep. Can fixed-width keep() sub-expressions + // use the simple_repeat_matcher? + }; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::unary_plus> + : unknown_width + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::dereference> + : unknown_width + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::logical_not> + : unknown_width + {}; + + template<typename Expr, typename Char, uint_t Min, uint_t Max> + struct width_of<Expr, Char, generic_quant_tag<Min, Max> > + : unknown_width + {}; + + template<typename Expr, typename Char, uint_t Count> + struct width_of<Expr, Char, generic_quant_tag<Count, Count> > + : mpl::if_c< + mpl::equal_to<unknown_width, width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> >::value + , unknown_width + , mpl::times< + width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + , mpl::size_t<Count> + > + >::type + {}; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::negate> + : width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + {}; + + // when complementing a set or an assertion, the width is that of the set (1) or the assertion (0) + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::complement> + : width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> + {}; + + // The comma is used in list-initialized sets, and the width of sets are 1 + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::comma> + : mpl::size_t<1> + {}; + + // The subscript operator[] is used for sets, as in set['a' | range('b','h')], + // or for actions as in (any >> expr)[ action ] + template<typename Expr, typename Char, typename Left> + struct width_of_subscript + : width_of<Left, Char> + {}; + + template<typename Expr, typename Char> + struct width_of_subscript<Expr, Char, set_initializer_type> + : mpl::size_t<1> + { + // If Left is "set" then make sure that Right has a width_of 1 + BOOST_MPL_ASSERT_RELATION( + 1 + , == + , (width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value)); + }; + + template<typename Expr, typename Char> + struct width_of<Expr, Char, proto::tag::subscript> + : width_of_subscript<Expr, Char, typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr> + {}; + +}}} // namespace boost::xpressive::detail + +#undef UNREF + +#endif diff --git a/boost/xpressive/detail/utility/algorithm.hpp b/boost/xpressive/detail/utility/algorithm.hpp new file mode 100644 index 0000000000..af722909c3 --- /dev/null +++ b/boost/xpressive/detail/utility/algorithm.hpp @@ -0,0 +1,174 @@ +/////////////////////////////////////////////////////////////////////////////// +// algorithm.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_UTILITY_ALGORITHM_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_ALGORITHM_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <climits> +#include <algorithm> +#include <boost/version.hpp> +#include <boost/range/end.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/size.hpp> +#include <boost/range/value_type.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// any +// +template<typename InIter, typename Pred> +inline bool any(InIter begin, InIter end, Pred pred) +{ + return end != std::find_if(begin, end, pred); +} + +/////////////////////////////////////////////////////////////////////////////// +// find_nth_if +// +template<typename FwdIter, typename Diff, typename Pred> +FwdIter find_nth_if(FwdIter begin, FwdIter end, Diff count, Pred pred) +{ + for(; begin != end; ++begin) + { + if(pred(*begin) && 0 == count--) + { + return begin; + } + } + + return end; +} + +/////////////////////////////////////////////////////////////////////////////// +// toi +// +template<typename InIter, typename Traits> +int toi(InIter &begin, InIter end, Traits const &tr, int radix = 10, int max = INT_MAX) +{ + detail::ignore_unused(tr); + int i = 0, c = 0; + for(; begin != end && -1 != (c = tr.value(*begin, radix)); ++begin) + { + if(max < ((i *= radix) += c)) + return i / radix; + } + return i; +} + +/////////////////////////////////////////////////////////////////////////////// +// advance_to +// +template<typename BidiIter, typename Diff> +inline bool advance_to_impl(BidiIter & iter, Diff diff, BidiIter end, std::bidirectional_iterator_tag) +{ + for(; 0 < diff && iter != end; --diff) + ++iter; + for(; 0 > diff && iter != end; ++diff) + --iter; + return 0 == diff; +} + +template<typename RandIter, typename Diff> +inline bool advance_to_impl(RandIter & iter, Diff diff, RandIter end, std::random_access_iterator_tag) +{ + if(0 < diff) + { + if((end - iter) < diff) + return false; + } + else if(0 > diff) + { + if((iter - end) < -diff) + return false; + } + iter += diff; + return true; +} + +template<typename Iter, typename Diff> +inline bool advance_to(Iter & iter, Diff diff, Iter end) +{ + return detail::advance_to_impl(iter, diff, end, typename iterator_category<Iter>::type()); +} + +/////////////////////////////////////////////////////////////////////////////// +// range_data +// +template<typename T> +struct range_data + : range_value<T> +{}; + +template<typename T> +struct range_data<T *> + : remove_const<T> +{}; + +template<typename T> std::ptrdiff_t is_null_terminated(T const &) { return 0; } +#if BOOST_VERSION >= 103500 +inline std::ptrdiff_t is_null_terminated(char const *) { return 1; } +#ifndef BOOST_XPRESSIVE_NO_WREGEX +inline std::ptrdiff_t is_null_terminated(wchar_t const *) { return 1; } +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// data_begin/data_end +// +template<typename Cont> +typename range_data<Cont>::type const *data_begin(Cont const &cont) +{ + return &*boost::begin(cont); +} + +template<typename Cont> +typename range_data<Cont>::type const *data_end(Cont const &cont) +{ + return &*boost::begin(cont) + boost::size(cont) - is_null_terminated(cont); +} + +template<typename Char, typename Traits, typename Alloc> +Char const *data_begin(std::basic_string<Char, Traits, Alloc> const &str) +{ + return str.data(); +} + +template<typename Char, typename Traits, typename Alloc> +Char const *data_end(std::basic_string<Char, Traits, Alloc> const &str) +{ + return str.data() + str.size(); +} + +template<typename Char> +Char const *data_begin(Char const *const &sz) +{ + return sz; +} + +template<typename Char> +Char const *data_end(Char const *const &sz) +{ + Char const *tmp = sz; + for(; *tmp; ++tmp) + ; + return tmp; +} + +}}} + +#endif diff --git a/boost/xpressive/detail/utility/any.hpp b/boost/xpressive/detail/utility/any.hpp new file mode 100644 index 0000000000..66ce4637da --- /dev/null +++ b/boost/xpressive/detail/utility/any.hpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// any.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_UTILITY_ANY_HPP_EAN_11_19_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_ANY_HPP_EAN_11_19_2005 + +#include <boost/version.hpp> + +#if BOOST_VERSION >= 103300 + +// In Boost 1.33+, we have a cons list in Fusion, so just include it. + +# if BOOST_VERSION >= 103500 +# include <boost/fusion/include/any.hpp> // Boost 1.35+ has Fusion2 +# else +# include <boost/spirit/fusion/algorithm/any.hpp> // Fusion1 +# endif + +#else + +# include <boost/spirit/fusion/sequence/begin.hpp> +# include <boost/spirit/fusion/sequence/end.hpp> +# include <boost/spirit/fusion/iterator/equal_to.hpp> +# include <boost/mpl/bool.hpp> +# include <boost/spirit/fusion/iterator/equal_to.hpp> +# include <boost/spirit/fusion/iterator/next.hpp> +# include <boost/spirit/fusion/iterator/deref.hpp> + +namespace boost { namespace fusion +{ + + namespace detail + { + template <typename First, typename Last, typename F> + inline bool + any(First const&, Last const&, F const&, mpl::true_) + { + return false; + } + + template <typename First, typename Last, typename F> + inline bool + any(First const& first, Last const& last, F const& f, mpl::false_) + { + if(f(*first)) + return true; + return detail::any(fusion::next(first), last, f + , meta::equal_to<BOOST_DEDUCED_TYPENAME meta::next<First>::type, Last>()); + } + } + + namespace meta + { + template <typename Sequence, typename F> + struct any + { + typedef bool type; + }; + } + + namespace function + { + struct any + { + template <typename Sequence, typename F> + struct apply + { + typedef bool type; + }; + + template <typename Sequence, typename F> + inline bool + operator()(Sequence const& seq, F const& f) const + { + return detail::any( + fusion::begin(seq) + , fusion::end(seq) + , f + , meta::equal_to< + BOOST_DEDUCED_TYPENAME meta::begin<Sequence>::type + , BOOST_DEDUCED_TYPENAME meta::end<Sequence>::type>()); + } + + template <typename Sequence, typename F> + inline bool + operator()(Sequence& seq, F const& f) const + { + return detail::any( + fusion::begin(seq) + , fusion::end(seq) + , f + , meta::equal_to< + BOOST_DEDUCED_TYPENAME meta::begin<Sequence>::type + , BOOST_DEDUCED_TYPENAME meta::end<Sequence>::type>()); + } + }; + } + + function::any const any = function::any(); +}} + +#endif + +#endif diff --git a/boost/xpressive/detail/utility/boyer_moore.hpp b/boost/xpressive/detail/utility/boyer_moore.hpp new file mode 100644 index 0000000000..08ca600b84 --- /dev/null +++ b/boost/xpressive/detail/utility/boyer_moore.hpp @@ -0,0 +1,198 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file boyer_moore.hpp +/// Contains the boyer-moore implementation. Note: this is *not* a general- +/// purpose boyer-moore implementation. It truncates the search string at +/// 256 characters, but it is sufficient for the needs of xpressive. +// +// 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_BOYER_MOORE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_BOYER_MOORE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#include <climits> // for UCHAR_MAX +#include <cstddef> // for std::ptrdiff_t +#include <utility> // for std::max +#include <vector> +#include <boost/mpl/bool.hpp> +#include <boost/noncopyable.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// boyer_moore +// +template<typename BidiIter, typename Traits> +struct boyer_moore + : noncopyable +{ + typedef typename iterator_value<BidiIter>::type char_type; + typedef Traits traits_type; + typedef has_fold_case<Traits> case_fold; + typedef typename Traits::string_type string_type; + + // initialize the Boyer-Moore search data structure, using the + // search sub-sequence to prime the pump. + boyer_moore(char_type const *begin, char_type const *end, Traits const &tr, bool icase) + : begin_(begin) + , last_(begin) + , fold_() + , find_fun_( + icase + ? (case_fold() ? &boyer_moore::find_nocase_fold_ : &boyer_moore::find_nocase_) + : &boyer_moore::find_ + ) + { + std::ptrdiff_t const uchar_max = UCHAR_MAX; + std::ptrdiff_t diff = std::distance(begin, end); + this->length_ = static_cast<unsigned char>((std::min)(diff, uchar_max)); + std::fill_n(static_cast<unsigned char *>(this->offsets_), uchar_max + 1, this->length_); + --this->length_; + + icase ? this->init_(tr, case_fold()) : this->init_(tr, mpl::false_()); + } + + BidiIter find(BidiIter begin, BidiIter end, Traits const &tr) const + { + return (this->*this->find_fun_)(begin, end, tr); + } + +private: + + void init_(Traits const &tr, mpl::false_) + { + for(unsigned char offset = this->length_; offset; --offset, ++this->last_) + { + this->offsets_[tr.hash(*this->last_)] = offset; + } + } + + void init_(Traits const &tr, mpl::true_) + { + this->fold_.reserve(this->length_ + 1); + for(unsigned char offset = this->length_; offset; --offset, ++this->last_) + { + this->fold_.push_back(tr.fold_case(*this->last_)); + for(typename string_type::const_iterator beg = this->fold_.back().begin(), end = this->fold_.back().end(); + beg != end; ++beg) + { + this->offsets_[tr.hash(*beg)] = offset; + } + } + this->fold_.push_back(tr.fold_case(*this->last_)); + } + + // case-sensitive Boyer-Moore search + BidiIter find_(BidiIter begin, BidiIter end, Traits const &tr) const + { + typedef typename boost::iterator_difference<BidiIter>::type diff_type; + diff_type const endpos = std::distance(begin, end); + diff_type offset = static_cast<diff_type>(this->length_); + + for(diff_type curpos = offset; curpos < endpos; curpos += offset) + { + std::advance(begin, offset); + + char_type const *pat_tmp = this->last_; + BidiIter str_tmp = begin; + + for(; tr.translate(*str_tmp) == *pat_tmp; --pat_tmp, --str_tmp) + { + if(pat_tmp == this->begin_) + { + return str_tmp; + } + } + + offset = this->offsets_[tr.hash(tr.translate(*begin))]; + } + + return end; + } + + // case-insensitive Boyer-Moore search + BidiIter find_nocase_(BidiIter begin, BidiIter end, Traits const &tr) const + { + typedef typename boost::iterator_difference<BidiIter>::type diff_type; + diff_type const endpos = std::distance(begin, end); + diff_type offset = static_cast<diff_type>(this->length_); + + for(diff_type curpos = offset; curpos < endpos; curpos += offset) + { + std::advance(begin, offset); + + char_type const *pat_tmp = this->last_; + BidiIter str_tmp = begin; + + for(; tr.translate_nocase(*str_tmp) == *pat_tmp; --pat_tmp, --str_tmp) + { + if(pat_tmp == this->begin_) + { + return str_tmp; + } + } + + offset = this->offsets_[tr.hash(tr.translate_nocase(*begin))]; + } + + return end; + } + + // case-insensitive Boyer-Moore search with case-folding + BidiIter find_nocase_fold_(BidiIter begin, BidiIter end, Traits const &tr) const + { + typedef typename boost::iterator_difference<BidiIter>::type diff_type; + diff_type const endpos = std::distance(begin, end); + diff_type offset = static_cast<diff_type>(this->length_); + + for(diff_type curpos = offset; curpos < endpos; curpos += offset) + { + std::advance(begin, offset); + + string_type const *pat_tmp = &this->fold_.back(); + BidiIter str_tmp = begin; + + for(; pat_tmp->end() != std::find(pat_tmp->begin(), pat_tmp->end(), *str_tmp); + --pat_tmp, --str_tmp) + { + if(pat_tmp == &this->fold_.front()) + { + return str_tmp; + } + } + + offset = this->offsets_[tr.hash(*begin)]; + } + + return end; + } + +private: + + char_type const *begin_; + char_type const *last_; + std::vector<string_type> fold_; + BidiIter (boyer_moore::*const find_fun_)(BidiIter, BidiIter, Traits const &) const; + unsigned char length_; + unsigned char offsets_[UCHAR_MAX + 1]; +}; + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/utility/chset/basic_chset.hpp b/boost/xpressive/detail/utility/chset/basic_chset.hpp new file mode 100644 index 0000000000..23316ce417 --- /dev/null +++ b/boost/xpressive/detail/utility/chset/basic_chset.hpp @@ -0,0 +1,172 @@ +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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_SPIRIT_BASIC_CHSET_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_SPIRIT_BASIC_CHSET_HPP_EAN_10_04_2005 + +/////////////////////////////////////////////////////////////////////////////// +#include <bitset> +#include <boost/mpl/bool.hpp> +#include <boost/xpressive/detail/utility/chset/range_run.ipp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////// +// +// basic_chset: basic character set implementation using range_run +// +/////////////////////////////////////////////////////////////////////////// +template<typename Char> +struct basic_chset +{ + basic_chset(); + basic_chset(basic_chset const &arg); + + bool empty() const; + void set(Char from, Char to); + template<typename Traits> + void set(Char from, Char to, Traits const &tr); + void set(Char c); + template<typename Traits> + void set(Char c, Traits const &tr); + + void clear(Char from, Char to); + template<typename Traits> + void clear(Char from, Char to, Traits const &tr); + void clear(Char c); + template<typename Traits> + void clear(Char c, Traits const &tr); + void clear(); + + template<typename Traits> + bool test(Char v, Traits const &tr, mpl::false_) const; // case-sensitive + template<typename Traits> + bool test(Char v, Traits const &tr, mpl::true_) const; // case-insensitive + + void inverse(); + void swap(basic_chset& x); + + basic_chset &operator |=(basic_chset const &x); + basic_chset &operator &=(basic_chset const &x); + basic_chset &operator -=(basic_chset const &x); + basic_chset &operator ^=(basic_chset const &x); + +private: + range_run<Char> rr_; +}; + +#if(CHAR_BIT == 8) + +/////////////////////////////////////////////////////////////////////////// +// +// basic_chset: specializations for 8 bit chars using std::bitset +// +/////////////////////////////////////////////////////////////////////////// +template<typename Char> +struct basic_chset_8bit +{ + basic_chset_8bit(); + basic_chset_8bit(basic_chset_8bit const &arg); + + bool empty() const; + + void set(Char from, Char to); + template<typename Traits> + void set(Char from, Char to, Traits const &tr); + void set(Char c); + template<typename Traits> + void set(Char c, Traits const &tr); + + void clear(Char from, Char to); + template<typename Traits> + void clear(Char from, Char to, Traits const &tr); + void clear(Char c); + template<typename Traits> + void clear(Char c, Traits const &tr); + void clear(); + + template<typename Traits> + bool test(Char v, Traits const &tr, mpl::false_) const; // case-sensitive + template<typename Traits> + bool test(Char v, Traits const &tr, mpl::true_) const; // case-insensitive + + void inverse(); + void swap(basic_chset_8bit& x); + + basic_chset_8bit &operator |=(basic_chset_8bit const &x); + basic_chset_8bit &operator &=(basic_chset_8bit const &x); + basic_chset_8bit &operator -=(basic_chset_8bit const &x); + basic_chset_8bit &operator ^=(basic_chset_8bit const &x); + + std::bitset<256> const &base() const; + +private: + std::bitset<256> bset_; // BUGBUG range-checking slows this down +}; + +///////////////////////////////// +template<> +struct basic_chset<char> + : basic_chset_8bit<char> +{ +}; + +///////////////////////////////// +template<> +struct basic_chset<signed char> + : basic_chset_8bit<signed char> +{ +}; + +///////////////////////////////// +template<> +struct basic_chset<unsigned char> + : basic_chset_8bit<unsigned char> +{ +}; + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// is_narrow_char +template<typename Char> +struct is_narrow_char + : mpl::false_ +{}; + +template<> +struct is_narrow_char<char> + : mpl::true_ +{}; + +template<> +struct is_narrow_char<signed char> + : mpl::true_ +{}; + +template<> +struct is_narrow_char<unsigned char> + : mpl::true_ +{}; + +/////////////////////////////////////////////////////////////////////////////// +// helpers +template<typename Char, typename Traits> +void set_char(basic_chset<Char> &chset, Char ch, Traits const &tr, bool icase); + +template<typename Char, typename Traits> +void set_range(basic_chset<Char> &chset, Char from, Char to, Traits const &tr, bool icase); + +template<typename Char, typename Traits> +void set_class(basic_chset<Char> &chset, typename Traits::char_class_type char_class, bool no, Traits const &tr); + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/chset/basic_chset.ipp b/boost/xpressive/detail/utility/chset/basic_chset.ipp new file mode 100644 index 0000000000..71b99133ee --- /dev/null +++ b/boost/xpressive/detail/utility/chset/basic_chset.ipp @@ -0,0 +1,409 @@ +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + Copyright (c) 2001-2003 Daniel Nuffer + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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_SPIRIT_BASIC_CHSET_IPP +#define BOOST_XPRESSIVE_SPIRIT_BASIC_CHSET_IPP + +/////////////////////////////////////////////////////////////////////////////// +#include <bitset> +#include <boost/xpressive/detail/utility/chset/basic_chset.hpp> + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// basic_chset: character set implementation +// +/////////////////////////////////////////////////////////////////////////////// +template<typename Char> +inline basic_chset<Char>::basic_chset() +{ +} + +////////////////////////////////// +template<typename Char> +inline basic_chset<Char>::basic_chset(basic_chset const &arg) + : rr_(arg.rr_) +{ +} + +////////////////////////////////// +template<typename Char> +inline bool basic_chset<Char>::empty() const +{ + return this->rr_.empty(); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline bool basic_chset<Char>::test(Char v, Traits const &, mpl::false_) const // case-sensitive +{ + return this->rr_.test(v); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline bool basic_chset<Char>::test(Char v, Traits const &tr, mpl::true_) const // case-insensitive +{ + return this->rr_.test(v, tr); +} + +////////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::set(Char from, Char to) +{ + this->rr_.set(range<Char>(from, to)); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset<Char>::set(Char from, Char to, Traits const &) +{ + this->rr_.set(range<Char>(from, to)); +} + +////////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::set(Char c) +{ + this->rr_.set(range<Char>(c, c)); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset<Char>::set(Char c, Traits const &) +{ + this->rr_.set(range<Char>(c, c)); +} + +////////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::clear(Char c) +{ + this->rr_.clear(range<Char>(c, c)); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset<Char>::clear(Char c, Traits const &) +{ + this->rr_.clear(range<Char>(c, c)); +} + +////////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::clear(Char from, Char to) +{ + this->rr_.clear(range<Char>(from, to)); +} + +////////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset<Char>::clear(Char from, Char to, Traits const &) +{ + this->rr_.clear(range<Char>(from, to)); +} + +////////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::clear() +{ + this->rr_.clear(); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::inverse() +{ + // BUGBUG is this right? Does this handle icase correctly? + basic_chset<Char> inv; + inv.set((std::numeric_limits<Char>::min)(), (std::numeric_limits<Char>::max)()); + inv -= *this; + this->swap(inv); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset<Char>::swap(basic_chset<Char> &that) +{ + this->rr_.swap(that.rr_); +} + +///////////////////////////////// +template<typename Char> +inline basic_chset<Char> & +basic_chset<Char>::operator |=(basic_chset<Char> const &that) +{ + typedef typename range_run<Char>::const_iterator const_iterator; + for(const_iterator iter = that.rr_.begin(); iter != that.rr_.end(); ++iter) + { + this->rr_.set(*iter); + } + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset<Char> & +basic_chset<Char>::operator &=(basic_chset<Char> const &that) +{ + basic_chset<Char> inv; + inv.set((std::numeric_limits<Char>::min)(), (std::numeric_limits<Char>::max)()); + inv -= that; + *this -= inv; + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset<Char> & +basic_chset<Char>::operator -=(basic_chset<Char> const &that) +{ + typedef typename range_run<Char>::const_iterator const_iterator; + for(const_iterator iter = that.rr_.begin(); iter != that.rr_.end(); ++iter) + { + this->rr_.clear(*iter); + } + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset<Char> & +basic_chset<Char>::operator ^=(basic_chset<Char> const &that) +{ + basic_chset bma = that; + bma -= *this; + *this -= that; + *this |= bma; + return *this; +} + +#if(CHAR_BIT == 8) + +/////////////////////////////////////////////////////////////////////////////// +// +// basic_chset: specializations for 8 bit chars using std::bitset +// +/////////////////////////////////////////////////////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char>::basic_chset_8bit() +{ +} + +///////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char>::basic_chset_8bit(basic_chset_8bit<Char> const &arg) + : bset_(arg.bset_) +{ +} + +///////////////////////////////// +template<typename Char> +inline bool basic_chset_8bit<Char>::empty() const +{ + return !this->bset_.any(); +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline bool basic_chset_8bit<Char>::test(Char v, Traits const &, mpl::false_) const // case-sensitive +{ + return this->bset_.test((unsigned char)v); +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline bool basic_chset_8bit<Char>::test(Char v, Traits const &tr, mpl::true_) const // case-insensitive +{ + return this->bset_.test((unsigned char)tr.translate_nocase(v)); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::set(Char from, Char to) +{ + for(int i = from; i <= to; ++i) + { + this->bset_.set((unsigned char)i); + } +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset_8bit<Char>::set(Char from, Char to, Traits const &tr) +{ + for(int i = from; i <= to; ++i) + { + this->bset_.set((unsigned char)tr.translate_nocase((Char)i)); + } +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::set(Char c) +{ + this->bset_.set((unsigned char)c); +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset_8bit<Char>::set(Char c, Traits const &tr) +{ + this->bset_.set((unsigned char)tr.translate_nocase(c)); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::clear(Char from, Char to) +{ + for(int i = from; i <= to; ++i) + { + this->bset_.reset((unsigned char)i); + } +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset_8bit<Char>::clear(Char from, Char to, Traits const &tr) +{ + for(int i = from; i <= to; ++i) + { + this->bset_.reset((unsigned char)tr.translate_nocase((Char)i)); + } +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::clear(Char c) +{ + this->bset_.reset((unsigned char)c); +} + +///////////////////////////////// +template<typename Char> +template<typename Traits> +inline void basic_chset_8bit<Char>::clear(Char c, Traits const &tr) +{ + this->bset_.reset((unsigned char)tr.tranlsate_nocase(c)); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::clear() +{ + this->bset_.reset(); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::inverse() +{ + this->bset_.flip(); +} + +///////////////////////////////// +template<typename Char> +inline void basic_chset_8bit<Char>::swap(basic_chset_8bit<Char> &that) +{ + std::swap(this->bset_, that.bset_); +} + +///////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char> & +basic_chset_8bit<Char>::operator |=(basic_chset_8bit<Char> const &that) +{ + this->bset_ |= that.bset_; + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char> & +basic_chset_8bit<Char>::operator &=(basic_chset_8bit<Char> const &that) +{ + this->bset_ &= that.bset_; + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char> & +basic_chset_8bit<Char>::operator -=(basic_chset_8bit<Char> const &that) +{ + this->bset_ &= ~that.bset_; + return *this; +} + +///////////////////////////////// +template<typename Char> +inline basic_chset_8bit<Char> & +basic_chset_8bit<Char>::operator ^=(basic_chset_8bit<Char> const &that) +{ + this->bset_ ^= that.bset_; + return *this; +} + +template<typename Char> +inline std::bitset<256> const & +basic_chset_8bit<Char>::base() const +{ + return this->bset_; +} + +#endif // if(CHAR_BIT == 8) + + +/////////////////////////////////////////////////////////////////////////////// +// helpers +template<typename Char, typename Traits> +inline void set_char(basic_chset<Char> &chset, Char ch, Traits const &tr, bool icase) +{ + icase ? chset.set(ch, tr) : chset.set(ch); +} + +template<typename Char, typename Traits> +inline void set_range(basic_chset<Char> &chset, Char from, Char to, Traits const &tr, bool icase) +{ + icase ? chset.set(from, to, tr) : chset.set(from, to); +} + +template<typename Char, typename Traits> +inline void set_class(basic_chset<Char> &chset, typename Traits::char_class_type char_class, bool no, Traits const &tr) +{ + BOOST_MPL_ASSERT_RELATION(1, ==, sizeof(Char)); + for(std::size_t i = 0; i <= UCHAR_MAX; ++i) + { + typedef typename std::char_traits<Char>::int_type int_type; + Char ch = std::char_traits<Char>::to_char_type(static_cast<int_type>(i)); + if(no != tr.isctype(ch, char_class)) + { + chset.set(ch); + } + } +} + +}}} // namespace boost::xpressive::detail + +#endif + diff --git a/boost/xpressive/detail/utility/chset/chset.hpp b/boost/xpressive/detail/utility/chset/chset.hpp new file mode 100644 index 0000000000..c10d466772 --- /dev/null +++ b/boost/xpressive/detail/utility/chset/chset.hpp @@ -0,0 +1,165 @@ +/////////////////////////////////////////////////////////////////////////////// +// chset.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_CHSET_CHSET_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_CHSET_CHSET_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <vector> +#include <boost/call_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> +#include <boost/xpressive/detail/utility/chset/basic_chset.ipp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// compound_charset +// +template<typename Traits> +struct compound_charset + : private basic_chset<typename Traits::char_type> +{ + typedef typename Traits::char_type char_type; + typedef basic_chset<char_type> base_type; + typedef Traits traits_type; + typedef typename Traits::char_class_type char_class_type; + + compound_charset() + : base_type() + , complement_(false) + , has_posix_(false) + , posix_yes_() + , posix_no_() + { + } + + /////////////////////////////////////////////////////////////////////////////// + // accessors + basic_chset<char_type> const &base() const + { + return *this; + } + + bool is_inverted() const + { + return this->complement_; + } + + char_class_type posix_yes() const + { + return this->posix_yes_; + } + + std::vector<char_class_type> const &posix_no() const + { + return this->posix_no_; + } + + /////////////////////////////////////////////////////////////////////////////// + // complement + void inverse() + { + this->complement_ = !this->complement_; + } + + /////////////////////////////////////////////////////////////////////////////// + // set + void set_char(char_type ch, Traits const &tr, bool icase) + { + icase ? this->base_type::set(ch, tr) : this->base_type::set(ch); + } + + void set_range(char_type from, char_type to, Traits const &tr, bool icase) + { + icase ? this->base_type::set(from, to, tr) : this->base_type::set(from, to); + } + + void set_class(char_class_type const &m, bool no) + { + this->has_posix_ = true; + + if(no) + { + this->posix_no_.push_back(m); + } + else + { + this->posix_yes_ |= m; + } + } + + /////////////////////////////////////////////////////////////////////////////// + // test + template<typename ICase> + bool test(char_type ch, Traits const &tr, ICase) const + { + return this->complement_ != + (this->base_type::test(ch, tr, ICase()) || + (this->has_posix_ && this->test_posix(ch, tr))); + } + +private: + + /////////////////////////////////////////////////////////////////////////////// + // not_posix_pred + struct not_posix_pred + { + char_type ch_; + Traits const *traits_ptr_; + + bool operator ()(typename call_traits<char_class_type>::param_type m) const + { + return !this->traits_ptr_->isctype(this->ch_, m); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // test_posix + bool test_posix(char_type ch, Traits const &tr) const + { + not_posix_pred const pred = {ch, &tr}; + return tr.isctype(ch, this->posix_yes_) + || any(this->posix_no_.begin(), this->posix_no_.end(), pred); + } + + bool complement_; + bool has_posix_; + char_class_type posix_yes_; + std::vector<char_class_type> posix_no_; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// helpers +template<typename Char, typename Traits> +inline void set_char(compound_charset<Traits> &chset, Char ch, Traits const &tr, bool icase) +{ + chset.set_char(ch, tr, icase); +} + +template<typename Char, typename Traits> +inline void set_range(compound_charset<Traits> &chset, Char from, Char to, Traits const &tr, bool icase) +{ + chset.set_range(from, to, tr, icase); +} + +template<typename Traits> +inline void set_class(compound_charset<Traits> &chset, typename Traits::char_class_type char_class, bool no, Traits const &) +{ + chset.set_class(char_class, no); +} + +}}} // namespace boost::xpressive::detail + +#endif + diff --git a/boost/xpressive/detail/utility/chset/range_run.hpp b/boost/xpressive/detail/utility/chset/range_run.hpp new file mode 100644 index 0000000000..f7d6adde15 --- /dev/null +++ b/boost/xpressive/detail/utility/chset/range_run.hpp @@ -0,0 +1,102 @@ +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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_SPIRIT_RANGE_RUN_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_SPIRIT_RANGE_RUN_HPP_EAN_10_04_2005 + +/////////////////////////////////////////////////////////////////////////////// +#include <vector> + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////// +// +// range class +// +// Implements a closed range of values. This class is used in +// the implementation of the range_run class. +// +// { Low level implementation detail } +// { Not to be confused with spirit::range } +// +/////////////////////////////////////////////////////////////////////////// +template<typename Char> +struct range +{ + range(Char first, Char last); + + bool is_valid() const; + bool includes(Char v) const; + bool includes(range const &r) const; + bool overlaps(range const &r) const; + void merge(range const &r); + + Char first_; + Char last_; +}; + +////////////////////////////////// +template<typename Char> +struct range_compare +{ + bool operator()(range<Char> const &x, range<Char> const &y) const + { + return x.first_ < y.first_; + } +}; + +/////////////////////////////////////////////////////////////////////////// +// +// range_run +// +// An implementation of a sparse bit (boolean) set. The set uses +// a sorted vector of disjoint ranges. This class implements the +// bare minimum essentials from which the full range of set +// operators can be implemented. The set is constructed from +// ranges. Internally, adjacent or overlapping ranges are +// coalesced. +// +// range_runs are very space-economical in situations where there +// are lots of ranges and a few individual disjoint values. +// Searching is O(log n) where n is the number of ranges. +// +// { Low level implementation detail } +// +/////////////////////////////////////////////////////////////////////////// +template<typename Char> +struct range_run +{ + typedef range<Char> range_type; + typedef std::vector<range_type> run_type; + typedef typename run_type::iterator iterator; + typedef typename run_type::const_iterator const_iterator; + + void swap(range_run& rr); + bool empty() const; + bool test(Char v) const; + template<typename Traits> + bool test(Char v, Traits const &tr) const; + void set(range_type const &r); + void clear(range_type const &r); + void clear(); + + const_iterator begin() const; + const_iterator end() const; + +private: + void merge(iterator iter, range_type const &r); + + run_type run_; +}; + +}}} // namespace boost::xpressive::detail + +#endif + diff --git a/boost/xpressive/detail/utility/chset/range_run.ipp b/boost/xpressive/detail/utility/chset/range_run.ipp new file mode 100644 index 0000000000..dfd321f786 --- /dev/null +++ b/boost/xpressive/detail/utility/chset/range_run.ipp @@ -0,0 +1,235 @@ +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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_SPIRIT_RANGE_RUN_IPP +#define BOOST_XPRESSIVE_SPIRIT_RANGE_RUN_IPP + +/////////////////////////////////////////////////////////////////////////////// +#include <algorithm> // for std::lower_bound +#include <boost/limits.hpp> +#include <boost/assert.hpp> +#include <boost/xpressive/detail/utility/chset/range_run.hpp> + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////// +// +// range class implementation +// +/////////////////////////////////////////////////////////////////////// +template<typename Char> +inline range<Char>::range(Char first, Char last) + : first_(first) + , last_(last) +{ +} + +////////////////////////////////// +template<typename Char> +inline bool range<Char>::is_valid() const +{ + return this->first_ <= this->last_; +} + +////////////////////////////////// +template<typename Char> +inline bool range<Char>::includes(range<Char> const &r) const +{ + return (this->first_ <= r.first_) && (this->last_ >= r.last_); +} + +////////////////////////////////// +template<typename Char> +inline bool range<Char>::includes(Char v) const +{ + return (this->first_ <= v) && (this->last_ >= v); +} + +////////////////////////////////// +template<typename Char> +inline bool range<Char>::overlaps(range<Char> const &r) const +{ + Char decr_first = (std::min)(this->first_, Char(this->first_-1)); + Char incr_last = (std::max)(this->last_, Char(this->last_+1)); + + return (decr_first <= r.last_) && (incr_last >= r.first_); +} + +////////////////////////////////// +template<typename Char> +inline void range<Char>::merge(range<Char> const &r) +{ + this->first_ = (std::min)(this->first_, r.first_); + this->last_ = (std::max)(this->last_, r.last_); +} + +/////////////////////////////////////////////////////////////////////// +// +// range_run class implementation +// +/////////////////////////////////////////////////////////////////////// +template<typename Char> +inline bool range_run<Char>::empty() const +{ + return this->run_.empty(); +} + +template<typename Char> +inline bool range_run<Char>::test(Char v) const +{ + if(this->run_.empty()) + { + return false; + } + + const_iterator iter = std::lower_bound( + this->run_.begin() + , this->run_.end() + , range<Char>(v, v) + , range_compare<Char>() + ); + + return (iter != this->run_.end() && iter->includes(v)) + || (iter != this->run_.begin() && (--iter)->includes(v)); +} + +template<typename Char> +template<typename Traits> +inline bool range_run<Char>::test(Char v, Traits const &tr) const +{ + const_iterator begin = this->run_.begin(); + const_iterator end = this->run_.end(); + + for(; begin != end; ++begin) + { + if(tr.in_range_nocase(begin->first_, begin->last_, v)) + { + return true; + } + } + return false; +} + +////////////////////////////////// +template<typename Char> +inline void range_run<Char>::swap(range_run<Char> &rr) +{ + this->run_.swap(rr.run_); +} + +////////////////////////////////// +template<typename Char> +void range_run<Char>::merge(iterator iter, range<Char> const &r) +{ + BOOST_ASSERT(iter != this->run_.end()); + iter->merge(r); + + iterator i = iter; + while(++i != this->run_.end() && iter->overlaps(*i)) + { + iter->merge(*i); + } + + this->run_.erase(++iter, i); +} + +////////////////////////////////// +template<typename Char> +void range_run<Char>::set(range<Char> const &r) +{ + BOOST_ASSERT(r.is_valid()); + if(!this->run_.empty()) + { + iterator iter = std::lower_bound(this->run_.begin(), this->run_.end(), r, range_compare<Char>()); + + if((iter != this->run_.end() && iter->includes(r)) || + (iter != this->run_.begin() && (iter - 1)->includes(r))) + { + return; + } + else if(iter != this->run_.begin() && (iter - 1)->overlaps(r)) + { + this->merge(--iter, r); + } + else if(iter != this->run_.end() && iter->overlaps(r)) + { + this->merge(iter, r); + } + else + { + this->run_.insert(iter, r); + } + } + else + { + this->run_.push_back(r); + } +} + +////////////////////////////////// +template<typename Char> +void range_run<Char>::clear(range<Char> const &r) +{ + BOOST_ASSERT(r.is_valid()); + if(!this->run_.empty()) + { + iterator iter = std::lower_bound(this->run_.begin(), this->run_.end(), r, range_compare<Char>()); + iterator left_iter; + + if((iter != this->run_.begin()) && + (left_iter = (iter - 1))->includes(r.first_)) + { + if(left_iter->last_ > r.last_) + { + Char save_last = left_iter->last_; + left_iter->last_ = r.first_-1; + this->run_.insert(iter, range<Char>(r.last_+1, save_last)); + return; + } + else + { + left_iter->last_ = r.first_-1; + } + } + + iterator i = iter; + for(; i != this->run_.end() && r.includes(*i); ++i) {} + if(i != this->run_.end() && i->includes(r.last_)) + { + i->first_ = r.last_+1; + } + this->run_.erase(iter, i); + } +} + +////////////////////////////////// +template<typename Char> +inline void range_run<Char>::clear() +{ + this->run_.clear(); +} + +////////////////////////////////// +template<typename Char> +inline typename range_run<Char>::const_iterator range_run<Char>::begin() const +{ + return this->run_.begin(); +} + +////////////////////////////////// +template<typename Char> +inline typename range_run<Char>::const_iterator range_run<Char>::end() const +{ + return this->run_.end(); +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/cons.hpp b/boost/xpressive/detail/utility/cons.hpp new file mode 100644 index 0000000000..50c43838b9 --- /dev/null +++ b/boost/xpressive/detail/utility/cons.hpp @@ -0,0 +1,309 @@ +/////////////////////////////////////////////////////////////////////////////// +// cons.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_UTILITY_CONS_HPP_EAN_11_19_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_CONS_HPP_EAN_11_19_2005 + +#include <boost/version.hpp> + +#if BOOST_VERSION >= 103300 + +// In Boost 1.33+, we have a cons list in Fusion, so just include it. + +# if BOOST_VERSION >= 103500 +# include <boost/fusion/include/cons.hpp> // Boost 1.35+ has Fusion2 +# else +# include <boost/spirit/fusion/sequence/cons.hpp> // Fusion1 +# endif + +#else + +// For earlier versions of Boost, put the definition of cons here +# include <boost/call_traits.hpp> +# include <boost/mpl/if.hpp> +# include <boost/mpl/eval_if.hpp> +# include <boost/mpl/identity.hpp> +# include <boost/type_traits/is_const.hpp> +# include <boost/type_traits/add_const.hpp> +# include <boost/type_traits/add_reference.hpp> +# include <boost/spirit/fusion/detail/config.hpp> +# include <boost/spirit/fusion/detail/access.hpp> +# include <boost/spirit/fusion/iterator/next.hpp> +# include <boost/spirit/fusion/iterator/equal_to.hpp> +# include <boost/spirit/fusion/iterator/as_fusion_iterator.hpp> +# include <boost/spirit/fusion/iterator/detail/iterator_base.hpp> +# include <boost/spirit/fusion/sequence/begin.hpp> +# include <boost/spirit/fusion/sequence/end.hpp> +# include <boost/spirit/fusion/sequence/as_fusion_sequence.hpp> +# include <boost/spirit/fusion/sequence/detail/sequence_base.hpp> + +namespace boost { namespace fusion +{ + struct nil; + + struct cons_tag; + + template <typename Car, typename Cdr> + struct cons; + + struct cons_iterator_tag; + + template <typename Cons> + struct cons_iterator; + + namespace cons_detail + { + template <typename Iterator> + struct deref_traits_impl + { + typedef typename Iterator::cons_type cons_type; + typedef typename cons_type::car_type value_type; + + typedef typename mpl::eval_if< + is_const<cons_type> + , add_reference<typename add_const<value_type>::type> + , add_reference<value_type> >::type + type; + + static type + call(Iterator const& i) + { + return detail::ref(i.cons.car); + } + }; + + template <typename Iterator> + struct next_traits_impl + { + typedef typename Iterator::cons_type cons_type; + typedef typename cons_type::cdr_type cdr_type; + + typedef cons_iterator< + typename mpl::eval_if< + is_const<cons_type> + , add_const<cdr_type> + , mpl::identity<cdr_type> + >::type> + type; + + static type + call(Iterator const& i) + { + return type(detail::ref(i.cons.cdr)); + } + }; + + template <typename Iterator> + struct value_traits_impl + { + typedef typename Iterator::cons_type cons_type; + typedef typename cons_type::car_type type; + }; + + template <typename Cons> + struct begin_traits_impl + { + typedef cons_iterator<Cons> type; + + static type + call(Cons& t) + { + return type(t); + } + }; + + template <typename Cons> + struct end_traits_impl + { + typedef cons_iterator< + typename mpl::if_<is_const<Cons>, nil const, nil>::type> + type; + + static type + call(Cons& t) + { + FUSION_RETURN_DEFAULT_CONSTRUCTED; + } + }; + } // namespace cons_detail + + namespace meta + { + template <typename Tag> + struct deref_impl; + + template <> + struct deref_impl<cons_iterator_tag> + { + template <typename Iterator> + struct apply : cons_detail::deref_traits_impl<Iterator> {}; + }; + + template <typename Tag> + struct next_impl; + + template <> + struct next_impl<cons_iterator_tag> + { + template <typename Iterator> + struct apply : cons_detail::next_traits_impl<Iterator> {}; + }; + + template <typename Tag> + struct value_impl; + + template <> + struct value_impl<cons_iterator_tag> + { + template <typename Iterator> + struct apply : cons_detail::value_traits_impl<Iterator> {}; + }; + + template <typename Tag> + struct begin_impl; + + template <> + struct begin_impl<cons_tag> + { + template <typename Sequence> + struct apply : cons_detail::begin_traits_impl<Sequence> + {}; + }; + + template <typename Tag> + struct end_impl; + + template <> + struct end_impl<cons_tag> + { + template <typename Sequence> + struct apply : cons_detail::end_traits_impl<Sequence> + {}; + }; + } // namespace meta + + template <typename Cons = nil> + struct cons_iterator : iterator_base<cons_iterator<Cons> > + { + typedef cons_iterator_tag tag; + typedef Cons cons_type; + + explicit cons_iterator(cons_type& cons_) + : cons(cons_) {} + + cons_type& cons; + }; + + template <> + struct cons_iterator<nil> : iterator_base<cons_iterator<nil> > + { + typedef cons_iterator_tag tag; + typedef nil cons_type; + cons_iterator() {} + explicit cons_iterator(nil const&) {} + }; + + template <> + struct cons_iterator<nil const> : iterator_base<cons_iterator<nil const> > + { + typedef cons_iterator_tag tag; + typedef nil const cons_type; + cons_iterator() {} + explicit cons_iterator(nil const&) {} + }; + + struct nil : sequence_base<nil> + { + typedef cons_tag tag; + typedef void_t car_type; + typedef void_t cdr_type; + }; + + template <typename Car, typename Cdr = nil> + struct cons : sequence_base<cons<Car,Cdr> > + { + typedef cons_tag tag; + typedef typename call_traits<Car>::value_type car_type; + typedef Cdr cdr_type; + + cons() + : car(), cdr() {} + + explicit cons( + typename call_traits<Car>::param_type car_ + , typename call_traits<Cdr>::param_type cdr_ = Cdr()) + : car(car_), cdr(cdr_) {} + + car_type car; + cdr_type cdr; + }; + + template <typename Car> + inline cons<Car> + make_cons(Car const& car) + { + return cons<Car>(car); + } + + template <typename Car, typename Cdr> + inline cons<Car, Cdr> + make_cons(Car const& car, Cdr const& cdr) + { + return cons<Car, Cdr>(car, cdr); + } +}} // namespace boost::fusion + +namespace boost { namespace mpl +{ + template <typename Tag> + struct begin_impl; + + template <typename Tag> + struct end_impl; + + template <> + struct begin_impl<fusion::cons_tag> + : fusion::meta::begin_impl<fusion::cons_tag> + { + }; + + template <> + struct end_impl<fusion::cons_tag> + : fusion::meta::end_impl<fusion::cons_tag> + { + }; + +}} // namespace boost::mpl + +#endif + +// Before Boost v1.33.1, Fusion cons lists were not valid MPL sequences. +#if BOOST_VERSION < 103301 +namespace boost { namespace mpl +{ + template<typename Iterator> + struct next; + + template<typename Cons> + struct next<fusion::cons_iterator<Cons> > + : fusion::cons_detail::next_traits_impl<fusion::cons_iterator<Cons> > + { + }; + + template<typename Iterator> + struct deref; + + template<typename Cons> + struct deref<fusion::cons_iterator<Cons> > + : fusion::cons_detail::value_traits_impl<fusion::cons_iterator<Cons> > + { + }; + +}} // namespace boost::mpl +#endif + +#endif diff --git a/boost/xpressive/detail/utility/counted_base.hpp b/boost/xpressive/detail/utility/counted_base.hpp new file mode 100644 index 0000000000..406c69db17 --- /dev/null +++ b/boost/xpressive/detail/utility/counted_base.hpp @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// (c) Copyright Andreas Huber Doenni 2002-2005, Eric Niebler 2006 +// Distributed under the Boost Software License, Version 1.0. (See accompany- +// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_XPRESSIVE_DETAIL_UTILITY_COUNTED_BASE_HPP_EAN_04_16_2006 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_COUNTED_BASE_HPP_EAN_04_16_2006 + +#include <boost/assert.hpp> +#include <boost/checked_delete.hpp> +#include <boost/detail/atomic_count.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + template<typename Derived> + struct counted_base_access; + + ////////////////////////////////////////////////////////////////////////////// + // counted_base + template<typename Derived> + struct counted_base + { + long use_count() const + { + return this->count_; + } + + protected: + counted_base() + : count_(0) + { + } + + counted_base(counted_base<Derived> const &) + : count_(0) + { + } + + counted_base &operator =(counted_base<Derived> const &) + { + return *this; + } + + private: + friend struct counted_base_access<Derived>; + mutable boost::detail::atomic_count count_; + }; + + ////////////////////////////////////////////////////////////////////////////// + // counted_base_access + template<typename Derived> + struct counted_base_access + { + static void add_ref(counted_base<Derived> const *that) + { + ++that->count_; + } + + static void release(counted_base<Derived> const *that) + { + BOOST_ASSERT(0 < that->count_); + if(0 == --that->count_) + { + boost::checked_delete(static_cast<Derived const *>(that)); + } + } + }; + + template<typename Derived> + inline void intrusive_ptr_add_ref(counted_base<Derived> const *that) + { + counted_base_access<Derived>::add_ref(that); + } + + template<typename Derived> + inline void intrusive_ptr_release(counted_base<Derived> const *that) + { + counted_base_access<Derived>::release(that); + } + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/dont_care.hpp b/boost/xpressive/detail/utility/dont_care.hpp new file mode 100644 index 0000000000..3e7a7a5f91 --- /dev/null +++ b/boost/xpressive/detail/utility/dont_care.hpp @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// dont_care.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_UTILITY_DONT_CARE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_DONT_CARE_HPP_EAN_10_04_2005 + +namespace boost { namespace xpressive { namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // for function arguments we don't care about + struct dont_care + { + dont_care() {} + + template<typename T> + dont_care(T const &) {} + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/utility/hash_peek_bitset.hpp b/boost/xpressive/detail/utility/hash_peek_bitset.hpp new file mode 100644 index 0000000000..56b41fc117 --- /dev/null +++ b/boost/xpressive/detail/utility/hash_peek_bitset.hpp @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////// +// hash_peek_bitset.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_HASH_PEEK_BITSET_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_HASH_PEEK_BITSET_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +# pragma warning(disable : 4127) // conditional expression constant +#endif + +#include <bitset> +#include <string> // for std::char_traits +#include <boost/xpressive/detail/utility/chset/basic_chset.ipp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// hash_peek_bitset +// +template<typename Char> +struct hash_peek_bitset +{ + typedef Char char_type; + typedef typename std::char_traits<char_type>::int_type int_type; + + hash_peek_bitset() + : icase_(false) + , bset_() + { + } + + std::size_t count() const + { + return this->bset_.count(); + } + + void set_all() + { + this->icase_ = false; + this->bset_.set(); + } + + template<typename Traits> + void set_char(char_type ch, bool icase, Traits const &tr) + { + if(this->test_icase_(icase)) + { + ch = icase ? tr.translate_nocase(ch) : tr.translate(ch); + this->bset_.set(tr.hash(ch)); + } + } + + template<typename Traits> + void set_range(char_type from, char_type to, bool no, bool icase, Traits const &tr) + { + int_type ifrom = std::char_traits<char_type>::to_int_type(from); + int_type ito = std::char_traits<char_type>::to_int_type(to); + BOOST_ASSERT(ifrom <= ito); + // bound the computational complexity. BUGBUG could set the inverse range + if(no || 256 < (ito - ifrom)) + { + this->set_all(); + } + else if(this->test_icase_(icase)) + { + for(int_type i = ifrom; i <= ito; ++i) + { + char_type ch = std::char_traits<char_type>::to_char_type(i); + ch = icase ? tr.translate_nocase(ch) : tr.translate(ch); + this->bset_.set(tr.hash(ch)); + } + } + } + + template<typename Traits> + void set_class(typename Traits::char_class_type char_class, bool no, Traits const &tr) + { + if(1 != sizeof(char_type)) + { + // wide character set, no efficient way of filling in the bitset, so set them all to 1 + this->set_all(); + } + else + { + for(std::size_t i = 0; i <= UCHAR_MAX; ++i) + { + char_type ch = std::char_traits<char_type>::to_char_type(static_cast<int_type>(i)); + if(no != tr.isctype(ch, char_class)) + { + this->bset_.set(i); + } + } + } + } + + void set_bitset(hash_peek_bitset<Char> const &that) + { + if(this->test_icase_(that.icase())) + { + this->bset_ |= that.bset_; + } + } + + void set_charset(basic_chset_8bit<Char> const &that, bool icase) + { + if(this->test_icase_(icase)) + { + this->bset_ |= that.base(); + } + } + + bool icase() const + { + return this->icase_; + } + + template<typename Traits> + bool test(char_type ch, Traits const &tr) const + { + ch = this->icase_ ? tr.translate_nocase(ch) : tr.translate(ch); + return this->bset_.test(tr.hash(ch)); + } + + template<typename Traits> + bool test(char_type ch, Traits const &tr, mpl::false_) const + { + BOOST_ASSERT(!this->icase_); + return this->bset_.test(tr.hash(tr.translate(ch))); + } + + template<typename Traits> + bool test(char_type ch, Traits const &tr, mpl::true_) const + { + BOOST_ASSERT(this->icase_); + return this->bset_.test(tr.hash(tr.translate_nocase(ch))); + } + +private: + + // Make sure all sub-expressions being merged have the same case-sensitivity + bool test_icase_(bool icase) + { + std::size_t count = this->bset_.count(); + + if(256 == count) + { + return false; // all set already, nothing to do + } + else if(0 != count && this->icase_ != icase) + { + this->set_all(); // icase mismatch! set all and bail + return false; + } + + this->icase_ = icase; + return true; + } + + bool icase_; + std::bitset<256> bset_; +}; + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/utility/ignore_unused.hpp b/boost/xpressive/detail/utility/ignore_unused.hpp new file mode 100644 index 0000000000..e7d3139f8a --- /dev/null +++ b/boost/xpressive/detail/utility/ignore_unused.hpp @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// ignore_unused.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_UTILITY_IGNORE_UNUSED_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_IGNORE_UNUSED_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "boost/proto/detail/ignore_unused.hpp" + +namespace boost { namespace xpressive { namespace detail +{ + using boost::proto::detail::ignore_unused; +}}} + +#endif + diff --git a/boost/xpressive/detail/utility/literals.hpp b/boost/xpressive/detail/utility/literals.hpp new file mode 100644 index 0000000000..67c9a42807 --- /dev/null +++ b/boost/xpressive/detail/utility/literals.hpp @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////////// +// literals.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_UTILITY_LITERALS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_LITERALS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> // for BOOST_STATIC_CONSTANT +#include <boost/cstdint.hpp> // for BOOST_STATIC_CONSTANT +#include <boost/detail/workaround.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// char_literal +// +template<typename Char, boost::intmax_t Ch, boost::intmax_t Wch> +struct char_literal; + +template<typename Char, boost::intmax_t Ch> +struct char_literal<Char, Ch, Ch> +{ + BOOST_STATIC_CONSTANT(boost::intmax_t, value = Ch); +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template<typename Char, boost::intmax_t Ch> +boost::intmax_t const char_literal<Char, Ch, Ch>::value; +#endif + +template<typename Ch> +struct string_literal; + +template<> +struct string_literal<char> +{ + static char const *pick(char const *cstr, wchar_t const *) + { + return cstr; + } + + static char pick(char ch, wchar_t) + { + return ch; + } +}; + +template<> +struct string_literal<wchar_t> +{ + static wchar_t const *pick(char const *, wchar_t const *cstr) + { + return cstr; + } + + static wchar_t pick(char, wchar_t ch) + { + return ch; + } +}; + +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) + +# define BOOST_XPR_CHAR_(Char, ch) ch +# define BOOST_XPR_CSTR_(Char, st) boost::xpressive::detail::string_literal<Char>::pick(st, L##st) + +#else + +# define BOOST_XPR_CHAR_(Char, ch) boost::xpressive::detail::char_literal<Char, ch, L##ch>::value +# define BOOST_XPR_CSTR_(Char, st) boost::xpressive::detail::string_literal<Char>::pick(st, L##st) + +#endif + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/never_true.hpp b/boost/xpressive/detail/utility/never_true.hpp new file mode 100644 index 0000000000..8c15ee4ff0 --- /dev/null +++ b/boost/xpressive/detail/utility/never_true.hpp @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// never_true.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_UTILITY_NEVER_TRUE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_NEVER_TRUE_HPP_EAN_10_04_2005 + +#include <boost/mpl/bool.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + // for use in static asserts + template<typename T> + struct never_true + : mpl::false_ + { + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/utility/save_restore.hpp b/boost/xpressive/detail/utility/save_restore.hpp new file mode 100644 index 0000000000..a9c2a2407e --- /dev/null +++ b/boost/xpressive/detail/utility/save_restore.hpp @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////// +// save_restore.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_UTILITY_SAVE_RESTORE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_SAVE_RESTORE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/noncopyable.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + template<typename T> + struct save_restore + : private noncopyable + { + explicit save_restore(T &t) + : ref(t) + , val(t) + { + } + + save_restore(T &t, T const &n) + : ref(t) + , val(t) + { + this->ref = n; + } + + ~save_restore() + { + this->ref = this->val; + } + + void restore() + { + this->ref = this->val; + } + + private: + T &ref; + T const val; + }; + +}}} + +#endif diff --git a/boost/xpressive/detail/utility/sequence_stack.hpp b/boost/xpressive/detail/utility/sequence_stack.hpp new file mode 100644 index 0000000000..aa251b64a8 --- /dev/null +++ b/boost/xpressive/detail/utility/sequence_stack.hpp @@ -0,0 +1,259 @@ +/////////////////////////////////////////////////////////////////////////////// +// sequence_stack.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_SEQUENCE_STACK_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4127) // conditional expression constant +#endif + +#include <algorithm> +#include <functional> + +namespace boost { namespace xpressive { namespace detail +{ + +struct fill_t {} const fill = {}; + +////////////////////////////////////////////////////////////////////////// +// sequence_stack +// +// For storing a stack of sequences of type T, where each sequence +// is guaranteed to be stored in contiguous memory. +template<typename T> +struct sequence_stack +{ +private: + static T *allocate(std::size_t size, T const &t) + { + std::size_t i = 0; + T *p = (T *)::operator new(size * sizeof(T)); + try + { + for(; i < size; ++i) + ::new((void *)(p+i)) T(t); + } + catch(...) + { + deallocate(p, i); + throw; + } + return p; + } + + static void deallocate(T *p, std::size_t i) + { + while(i-- > 0) + (p+i)->~T(); + ::operator delete(p); + } + + struct chunk + { + chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next) + : begin_(allocate(size, t)) + , curr_(begin_ + count) + , end_(begin_ + size) + , back_(back) + , next_(next) + { + if(this->back_) + this->back_->next_ = this; + if(this->next_) + this->next_->back_ = this; + } + + ~chunk() + { + deallocate(this->begin_, this->size()); + } + + std::size_t size() const + { + return static_cast<std::size_t>(this->end_ - this->begin_); + } + + T *const begin_, *curr_, *const end_; + chunk *back_, *next_; + + private: + chunk &operator =(chunk const &); + }; + + chunk *current_chunk_; + + // Cache these for faster access + T *begin_; + T *curr_; + T *end_; + + T *grow_(std::size_t count, T const &t) + { + if(this->current_chunk_) + { + // write the cached value of current into the expr. + // OK to do this even if later statements throw. + this->current_chunk_->curr_ = this->curr_; + + // Do we have a expr with enough available memory already? + if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size()) + { + this->current_chunk_ = this->current_chunk_->next_; + this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count; + this->end_ = this->current_chunk_->end_; + this->begin_ = this->current_chunk_->begin_; + std::fill_n(this->begin_, count, t); + return this->begin_; + } + + // grow exponentially + std::size_t new_size = (std::max)(count, static_cast<std::size_t>(this->current_chunk_->size() * 1.5)); + + // Create a new expr and insert it into the list + this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_); + } + else + { + // first chunk is 256 + std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U)); + + // Create a new expr and insert it into the list + this->current_chunk_ = new chunk(new_size, t, count, 0, 0); + } + + this->begin_ = this->current_chunk_->begin_; + this->curr_ = this->current_chunk_->curr_; + this->end_ = this->current_chunk_->end_; + return this->begin_; + } + + void unwind_chunk_() + { + // write the cached value of curr_ into current_chunk_ + this->current_chunk_->curr_ = this->begin_; + // make the previous chunk the current + this->current_chunk_ = this->current_chunk_->back_; + + // update the cache + this->begin_ = this->current_chunk_->begin_; + this->curr_ = this->current_chunk_->curr_; + this->end_ = this->current_chunk_->end_; + } + + bool in_current_chunk(T *ptr) const + { + return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_); + } + +public: + sequence_stack() + : current_chunk_(0) + , begin_(0) + , curr_(0) + , end_(0) + { + } + + ~sequence_stack() + { + this->clear(); + } + + // walk to the front of the linked list + void unwind() + { + if(this->current_chunk_) + { + while(this->current_chunk_->back_) + { + this->current_chunk_->curr_ = this->current_chunk_->begin_; + this->current_chunk_ = this->current_chunk_->back_; + } + + this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_; + this->end_ = this->current_chunk_->end_; + } + } + + void clear() + { + // walk to the front of the list + this->unwind(); + + // delete the list + for(chunk *next; this->current_chunk_; this->current_chunk_ = next) + { + next = this->current_chunk_->next_; + delete this->current_chunk_; + } + + this->begin_ = this->curr_ = this->end_ = 0; + } + + T *push_sequence(std::size_t count, T const &t) + { + // This is the ptr to return + T *ptr = this->curr_; + + // Advance the high-water mark + this->curr_ += count; + + // Check to see if we have overflowed this buffer + if(std::less<void*>()(this->end_, this->curr_)) + { + // oops, back this out. + this->curr_ = ptr; + + // allocate a new block and return a ptr to the new memory + return this->grow_(count, t); + } + + return ptr; + } + + T *push_sequence(std::size_t count, T const &t, fill_t) + { + T *ptr = this->push_sequence(count, t); + std::fill_n(ptr, count, t); + return ptr; + } + + void unwind_to(T *ptr) + { + while(!this->in_current_chunk(ptr)) + { + // completely unwind the current chunk, move to the previous chunk + this->unwind_chunk_(); + } + this->current_chunk_->curr_ = this->curr_ = ptr; + } + + // shrink-to-fit: remove any unused nodes in the chain + void conserve() + { + if(this->current_chunk_) + { + for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next) + { + next = this->current_chunk_->next_->next_; + delete this->current_chunk_->next_; + } + } + } +}; + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/utility/symbols.hpp b/boost/xpressive/detail/utility/symbols.hpp new file mode 100644 index 0000000000..b1c4213a6c --- /dev/null +++ b/boost/xpressive/detail/utility/symbols.hpp @@ -0,0 +1,278 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file symbols.hpp +/// Contains the Ternary Search Trie implementation. +/// Based on the following papers: +/// J. Bentley and R. Sedgewick. (1998) Ternary search trees. Dr. Dobbs Journal +/// G. Badr and B.J. Oommen. (2005) Self-Adjusting of Ternary Search Tries Using +/// Conditional Rotations and Randomized Heuristics +// +// Copyright 2007 David Jenkins. +// Copyright 2007 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_SYMBOLS_HPP_DRJ_06_11_2007 +#define BOOST_XPRESSIVE_DETAIL_SYMBOLS_HPP_DRJ_06_11_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/noncopyable.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/value_type.hpp> +#include <boost/range/const_iterator.hpp> +#include <boost/shared_ptr.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // symbols (using a ternary search trie) + // + template<typename Map> + struct symbols + { + typedef typename range_value<Map>::type::first_type key_type; + typedef typename range_value<Map>::type::second_type value_type; + typedef typename range_value<key_type>::type char_type; + typedef typename range_const_iterator<Map>::type iterator; + typedef typename range_const_iterator<key_type>::type key_iterator; + typedef value_type const *result_type; + + // copies of this symbol table share the TST + + template<typename Trans> + void load(Map const &map, Trans trans) + { + iterator begin = boost::begin(map); + iterator end = boost::end(map); + node* root_p = this->root.get(); + for(; begin != end; ++begin) + { + key_iterator kbegin = boost::begin(begin->first); + key_iterator kend = boost::end(begin->first); + root_p = this->insert(root_p, kbegin, kend, &begin->second, trans); + } + this->root.reset(root_p); + } + + template<typename BidiIter, typename Trans> + result_type operator ()(BidiIter &begin, BidiIter end, Trans trans) const + { + return this->search(begin, end, trans, this->root.get()); + } + + template<typename Sink> + void peek(Sink const &sink) const + { + this->peek_(this->root.get(), sink); + } + + private: + /////////////////////////////////////////////////////////////////////////////// + // struct node : a node in the TST. + // The "eq" field stores the result pointer when ch is zero. + // + struct node + : boost::noncopyable + { + node(char_type c) + : ch(c) + , lo(0) + , eq(0) + , hi(0) + #ifdef BOOST_DISABLE_THREADS + , tau(0) + #endif + {} + + ~node() + { + delete lo; + if (ch) + delete eq; + delete hi; + } + + void swap(node& that) + { + std::swap(ch, that.ch); + std::swap(lo, that.lo); + std::swap(eq, that.eq); + std::swap(hi, that.hi); + #ifdef BOOST_DISABLE_THREADS + std::swap(tau, that.tau); + #endif + } + + char_type ch; + node* lo; + union + { + node* eq; + result_type result; + }; + node* hi; + #ifdef BOOST_DISABLE_THREADS + long tau; + #endif + }; + + /////////////////////////////////////////////////////////////////////////////// + // insert : insert a string into the TST + // + template<typename Trans> + node* insert(node* p, key_iterator &begin, key_iterator end, result_type r, Trans trans) const + { + char_type c1 = 0; + + if(begin != end) + { + c1 = trans(*begin); + } + + if(!p) + { + p = new node(c1); + } + + if(c1 < p->ch) + { + p->lo = this->insert(p->lo, begin, end, r, trans); + } + else if(c1 == p->ch) + { + if(0 == c1) + { + p->result = r; + } + else + { + p->eq = this->insert(p->eq, ++begin, end, r, trans); + } + } + else + { + p->hi = this->insert(p->hi, begin, end, r, trans); + } + + return p; + } + + #ifdef BOOST_DISABLE_THREADS + /////////////////////////////////////////////////////////////////////////////// + // conditional rotation : the goal is to minimize the overall + // weighted path length of each binary search tree + // + bool cond_rotation(bool left, node* const i, node* const j) const + { + // don't rotate top node in binary search tree + if (i == j) + return false; + // calculate psi (the rotation condition) + node* const k = (left ? i->hi : i->lo); + long psi = 2*i->tau - j->tau - (k ? k->tau : 0); + if (psi <= 0) + return false; + + // recalculate the tau values + j->tau += -i->tau + (k ? k->tau : 0); + i->tau += j->tau - (k ? k->tau : 0); + // fixup links and swap nodes + if (left) + { + j->lo = k; + i->hi = i; + } + else + { + j->hi = k; + i->lo = i; + } + (*i).swap(*j); + return true; + } + #endif + + /////////////////////////////////////////////////////////////////////////////// + // search : find a string in the TST + // + template<typename BidiIter, typename Trans> + result_type search(BidiIter &begin, BidiIter end, Trans trans, node* p) const + { + result_type r = 0; + node* p2 = p; + bool left = false; + char_type c1 = (begin != end ? trans(*begin) : 0); + while(p) + { + #ifdef BOOST_DISABLE_THREADS + ++p->tau; + #endif + if(c1 == p->ch) + { + // conditional rotation test + #ifdef BOOST_DISABLE_THREADS + if (this->cond_rotation(left, p, p2)) + p = p2; + #endif + if (0 == p->ch) + { + // it's a match! + r = p->result; + } + if(begin == end) + break; + ++begin; + p = p->eq; + // search for the longest match first + r = search(begin,end,trans,p); + if (0 == r) + { + // search for a match ending here + r = search(end,end,trans,p); + if (0 == r) + { + --begin; + } + } + break; + } + else if(c1 < p->ch) + { + left = true; + p2 = p; + p = p->lo; + } + else // (c1 > p->ch) + { + left = false; + p2 = p; + p = p->hi; + } + } + return r; + } + + template<typename Sink> + void peek_(node const *const &p, Sink const &sink) const + { + if(p) + { + sink(p->ch); + this->peek_(p->lo, sink); + this->peek_(p->hi, sink); + } + } + + boost::shared_ptr<node> root; + }; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/tracking_ptr.hpp b/boost/xpressive/detail/utility/tracking_ptr.hpp new file mode 100644 index 0000000000..7f29ba155d --- /dev/null +++ b/boost/xpressive/detail/utility/tracking_ptr.hpp @@ -0,0 +1,494 @@ +/////////////////////////////////////////////////////////////////////////////// +// tracking_ptr.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_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER +# include <iostream> +#endif +#include <set> +#include <functional> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/detail/atomic_count.hpp> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/iterator/filter_iterator.hpp> +#include <boost/type_traits/is_base_and_derived.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +template<typename Type> +struct tracking_ptr; + +template<typename Derived> +struct enable_reference_tracking; + +/////////////////////////////////////////////////////////////////////////////// +// weak_iterator +// steps through a set of weak_ptr, converts to shared_ptrs on the fly and +// removes from the set the weak_ptrs that have expired. +template<typename Derived> +struct weak_iterator + : iterator_facade + < + weak_iterator<Derived> + , shared_ptr<Derived> const + , std::forward_iterator_tag + > +{ + typedef std::set<weak_ptr<Derived> > set_type; + typedef typename set_type::iterator base_iterator; + + weak_iterator() + : cur_() + , iter_() + , set_(0) + { + } + + weak_iterator(base_iterator iter, set_type *set) + : cur_() + , iter_(iter) + , set_(set) + { + this->satisfy_(); + } + +private: + friend class boost::iterator_core_access; + + shared_ptr<Derived> const &dereference() const + { + return this->cur_; + } + + void increment() + { + ++this->iter_; + this->satisfy_(); + } + + bool equal(weak_iterator<Derived> const &that) const + { + return this->iter_ == that.iter_; + } + + void satisfy_() + { + while(this->iter_ != this->set_->end()) + { + this->cur_ = this->iter_->lock(); + if(this->cur_) + return; + base_iterator tmp = this->iter_++; + this->set_->erase(tmp); + } + this->cur_.reset(); + } + + shared_ptr<Derived> cur_; + base_iterator iter_; + set_type *set_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// filter_self +// for use with a filter_iterator to filter a node out of a list of dependencies +template<typename Derived> +struct filter_self + : std::unary_function<shared_ptr<Derived>, bool> +{ + filter_self(enable_reference_tracking<Derived> *self) + : self_(self) + { + } + + bool operator ()(shared_ptr<Derived> const &that) const + { + return this->self_ != that.get(); + } + +private: + enable_reference_tracking<Derived> *self_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// swap without bringing in std::swap -- must be found by ADL. +template<typename T> +void adl_swap(T &t1, T &t2) +{ + swap(t1, t2); +} + +/////////////////////////////////////////////////////////////////////////////// +// enable_reference_tracking +// inherit from this type to enable reference tracking for a type. You can +// then use tracking_ptr (below) as a holder for derived objects. +// +template<typename Derived> +struct enable_reference_tracking +{ + typedef std::set<shared_ptr<Derived> > references_type; + typedef std::set<weak_ptr<Derived> > dependents_type; + + void tracking_copy(Derived const &that) + { + if(&this->derived_() != &that) + { + this->raw_copy_(that); + this->tracking_update(); + } + } + + void tracking_clear() + { + this->raw_copy_(Derived()); + } + + // called automatically as a result of a tracking_copy(). Must be called explicitly + // if you change the references without calling tracking_copy(). + void tracking_update() + { + // add "this" as a dependency to all the references + this->update_references_(); + // notify our dependencies that we have new references + this->update_dependents_(); + } + + void track_reference(enable_reference_tracking<Derived> &that) + { + // avoid some unbounded memory growth in certain circumstances by + // opportunistically removing stale dependencies from "that" + that.purge_stale_deps_(); + // add "that" as a reference + this->refs_.insert(that.self_); + // also inherit that's references + this->refs_.insert(that.refs_.begin(), that.refs_.end()); + } + + long use_count() const + { + return this->cnt_; + } + + void add_ref() + { + ++this->cnt_; + } + + void release() + { + BOOST_ASSERT(0 < this->cnt_); + if(0 == --this->cnt_) + { + this->refs_.clear(); + this->self_.reset(); + } + } + + //{{AFX_DEBUG + #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER + friend std::ostream &operator <<(std::ostream &sout, enable_reference_tracking<Derived> const &that) + { + that.dump_(sout); + return sout; + } + #endif + //}}AFX_DEBUG + +protected: + + enable_reference_tracking() + : refs_() + , deps_() + , self_() + , cnt_(0) + { + } + + enable_reference_tracking(enable_reference_tracking<Derived> const &that) + : refs_() + , deps_() + , self_() + , cnt_(0) + { + this->operator =(that); + } + + enable_reference_tracking<Derived> &operator =(enable_reference_tracking<Derived> const &that) + { + references_type(that.refs_).swap(this->refs_); + return *this; + } + + void swap(enable_reference_tracking<Derived> &that) + { + this->refs_.swap(that.refs_); + } + +private: + friend struct tracking_ptr<Derived>; + + Derived &derived_() + { + return *static_cast<Derived *>(this); + } + + void raw_copy_(Derived that) + { + detail::adl_swap(this->derived_(), that); + } + + bool has_deps_() const + { + return !this->deps_.empty(); + } + + void update_references_() + { + typename references_type::iterator cur = this->refs_.begin(); + typename references_type::iterator end = this->refs_.end(); + for(; cur != end; ++cur) + { + // for each reference, add this as a dependency + (*cur)->track_dependency_(*this); + } + } + + void update_dependents_() + { + // called whenever this regex object changes (i.e., is assigned to). it walks + // the list of dependent regexes and updates *their* lists of references, + // thereby spreading out the reference counting responsibility evenly. + weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_); + weak_iterator<Derived> end(this->deps_.end(), &this->deps_); + + for(; cur != end; ++cur) + { + (*cur)->track_reference(*this); + } + } + + void track_dependency_(enable_reference_tracking<Derived> &dep) + { + if(this == &dep) // never add ourself as a dependency + return; + + // add dep as a dependency + this->deps_.insert(dep.self_); + + filter_self<Derived> not_self(this); + weak_iterator<Derived> begin(dep.deps_.begin(), &dep.deps_); + weak_iterator<Derived> end(dep.deps_.end(), &dep.deps_); + + // also inherit dep's dependencies + this->deps_.insert( + make_filter_iterator(not_self, begin, end) + , make_filter_iterator(not_self, end, end) + ); + } + + void purge_stale_deps_() + { + weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_); + weak_iterator<Derived> end(this->deps_.end(), &this->deps_); + + for(; cur != end; ++cur) + ; + } + + //{{AFX_DEBUG + #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER + void dump_(std::ostream &sout) const; + #endif + //}}AFX_DEBUG + + references_type refs_; + dependents_type deps_; + shared_ptr<Derived> self_; + boost::detail::atomic_count cnt_; +}; + +template<typename Derived> +inline void intrusive_ptr_add_ref(enable_reference_tracking<Derived> *p) +{ + p->add_ref(); +} + +template<typename Derived> +inline void intrusive_ptr_release(enable_reference_tracking<Derived> *p) +{ + p->release(); +} + +//{{AFX_DEBUG +#ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER +/////////////////////////////////////////////////////////////////////////////// +// dump_ +// +template<typename Derived> +inline void enable_reference_tracking<Derived>::dump_(std::ostream &sout) const +{ + shared_ptr<Derived> this_ = this->self_; + sout << "0x" << (void*)this << " cnt=" << this_.use_count()-1 << " refs={"; + typename references_type::const_iterator cur1 = this->refs_.begin(); + typename references_type::const_iterator end1 = this->refs_.end(); + for(; cur1 != end1; ++cur1) + { + sout << "0x" << (void*)&**cur1 << ','; + } + sout << "} deps={"; + typename dependents_type::const_iterator cur2 = this->deps_.begin(); + typename dependents_type::const_iterator end2 = this->deps_.end(); + for(; cur2 != end2; ++cur2) + { + // ericne, 27/nov/05: CW9_4 doesn't like if(shared_ptr x = y) + shared_ptr<Derived> dep = cur2->lock(); + if(dep.get()) + { + sout << "0x" << (void*)&*dep << ','; + } + } + sout << '}'; +} +#endif +//}}AFX_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// tracking_ptr +// holder for a reference-tracked type. Does cycle-breaking, lazy initialization +// and copy-on-write. TODO: implement move semantics. +// +template<typename Type> +struct tracking_ptr +{ + BOOST_MPL_ASSERT((is_base_and_derived<enable_reference_tracking<Type>, Type>)); + typedef Type element_type; + + tracking_ptr() + : impl_() + { + } + + tracking_ptr(tracking_ptr<element_type> const &that) + : impl_() + { + this->operator =(that); + } + + tracking_ptr<element_type> &operator =(tracking_ptr<element_type> const &that) + { + // Note: the copy-and-swap idiom doesn't work here if has_deps_()==true + // because it invalidates references to the element_type object. + if(this != &that) + { + if(that) + { + if(that.has_deps_() || this->has_deps_()) + { + this->fork_(); // deep copy, forks data if necessary + this->impl_->tracking_copy(*that); + } + else + { + this->impl_ = that.impl_; // shallow, copy-on-write + } + } + else if(*this) + { + this->impl_->tracking_clear(); + } + } + return *this; + } + + // NOTE: this does *not* do tracking. Can't provide a non-throwing swap that tracks references + void swap(tracking_ptr<element_type> &that) // throw() + { + this->impl_.swap(that.impl_); + } + + // calling this forces this->impl_ to fork. + shared_ptr<element_type> const &get() const + { + if(intrusive_ptr<element_type> impl = this->fork_()) + { + this->impl_->tracking_copy(*impl); + } + return this->impl_->self_; + } + + #if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530) + typedef bool unspecified_bool_type; + #else + typedef typename intrusive_ptr<element_type>::unspecified_bool_type unspecified_bool_type; + #endif + + // smart-pointer operators + operator unspecified_bool_type() const + { + return this->impl_; + } + + bool operator !() const + { + return !this->impl_; + } + + // Since this does not un-share the data, it returns a ptr-to-const + element_type const *operator ->() const + { + return get_pointer(this->impl_); + } + + // Since this does not un-share the data, it returns a ref-to-const + element_type const &operator *() const + { + return *this->impl_; + } + +private: + + // calling this forces impl_ to fork. + intrusive_ptr<element_type> fork_() const + { + intrusive_ptr<element_type> impl; + if(!this->impl_ || 1 != this->impl_->use_count()) + { + impl = this->impl_; + BOOST_ASSERT(!this->has_deps_()); + shared_ptr<element_type> simpl(new element_type); + this->impl_ = get_pointer(simpl->self_ = simpl); + } + return impl; + } + + // does anybody have a dependency on us? + bool has_deps_() const + { + return this->impl_ && this->impl_->has_deps_(); + } + + // mutable to allow lazy initialization + mutable intrusive_ptr<element_type> impl_; +}; + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/detail/utility/traits_utils.hpp b/boost/xpressive/detail/utility/traits_utils.hpp new file mode 100644 index 0000000000..18e3e609ff --- /dev/null +++ b/boost/xpressive/detail/utility/traits_utils.hpp @@ -0,0 +1,145 @@ +/////////////////////////////////////////////////////////////////////////////// +// traits_utils.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_UTILITY_TRAITS_UTILS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_TRAITS_UTILS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#include <string> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + + /////////////////////////////////////////////////////////////////////////////// + // char_cast + // + template<typename ToChar, typename FromChar, typename Traits> + inline ToChar + char_cast(FromChar from, Traits const &, typename enable_if<is_same<ToChar, FromChar> >::type * = 0) + { + return from; + } + + template<typename ToChar, typename FromChar, typename Traits> + inline ToChar + char_cast(FromChar from, Traits const &tr, typename disable_if<is_same<ToChar, FromChar> >::type * = 0) + { + BOOST_MPL_ASSERT((is_same<FromChar, char>)); + return tr.widen(from); + } + + /////////////////////////////////////////////////////////////////////////////// + // widen_fun + // + template<typename Traits> + struct widen_fun + { + typedef typename Traits::char_type result_type; + explicit widen_fun(Traits const &tr) + : traits_(tr) + {} + + result_type operator()(char ch) const + { + return this->traits_.widen(ch); + } + + Traits const &traits_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // string_cast_ + // + template< + typename To + , typename From + , typename ToChar = typename detail::range_data<To>::type + , typename FromChar = typename detail::range_data<From>::type + > + struct string_cast_ + { + BOOST_MPL_ASSERT((is_same<FromChar, char>)); + typedef To const result_type; + template<typename Traits> + result_type operator()(From const &from, Traits const &tr) const + { + widen_fun<Traits> widen(tr); + To to( + boost::make_transform_iterator(detail::data_begin(from), widen) + , boost::make_transform_iterator(detail::data_end(from), widen) + ); + return to; + } + }; + + template<typename To, typename From, typename Char> + struct string_cast_<To, From, Char, Char> + { + typedef To const result_type; + template<typename Traits> + result_type operator()(From const &from, Traits const &) const + { + To to(detail::data_begin(from), detail::data_end(from)); + return to; + } + }; + + template<typename From, typename Char> + struct string_cast_<From, From, Char, Char> + { + typedef From const &result_type; + template<typename Traits> + result_type operator()(From const &from, Traits const &) const + { + return from; + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // string_cast + // + template<typename To, typename From, typename Traits> + typename string_cast_<To, From>::result_type + string_cast(From const &from, Traits const &tr) + { + return string_cast_<To, From>()(from, tr); + } + + /////////////////////////////////////////////////////////////////////////////// + // translate + // + template<typename Char, typename Traits> + inline Char translate(Char ch, Traits const &tr, mpl::false_) // case-sensitive + { + return tr.translate(ch); + } + + template<typename Char, typename Traits> + inline Char translate(Char ch, Traits const &tr, mpl::true_) // case-insensitive + { + return tr.translate_nocase(ch); + } + +}}} // namespace boost::xpressive::detail + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma warning(pop) +#endif + +#endif diff --git a/boost/xpressive/detail/utility/width.hpp b/boost/xpressive/detail/utility/width.hpp new file mode 100644 index 0000000000..3fc10c76a5 --- /dev/null +++ b/boost/xpressive/detail/utility/width.hpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// width.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_UTILITY_WIDTH_HPP_EAN_04_07_2006 +#define BOOST_XPRESSIVE_DETAIL_UTILITY_WIDTH_HPP_EAN_04_07_2006 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <climits> // for INT_MAX +#include <boost/mpl/size_t.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +typedef mpl::size_t<INT_MAX / 2 - 1> unknown_width; +struct width; +bool is_unknown(width const &that); + +/////////////////////////////////////////////////////////////////////////////// +// width +struct width +{ + width(std::size_t val = 0) + : value_(val) + { + } + + bool operator !() const + { + return !this->value_; + } + + width &operator +=(width const &that) + { + this->value_ = + !is_unknown(*this) && !is_unknown(that) + ? this->value_ + that.value_ + : unknown_width(); + return *this; + } + + width &operator |=(width const &that) + { + this->value_ = + this->value_ == that.value_ + ? this->value_ + : unknown_width(); + return *this; + } + + std::size_t value() const + { + return this->value_; + } + +private: + std::size_t value_; +}; + +inline bool is_unknown(width const &that) +{ + return unknown_width::value == that.value(); +} + +inline bool operator ==(width const &left, width const &right) +{ + return left.value() == right.value(); +} + +inline bool operator !=(width const &left, width const &right) +{ + return left.value() != right.value(); +} + +inline width operator +(width left, width const &right) +{ + return left += right; +} + +inline width operator |(width left, width const &right) +{ + return left |= right; +} + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/match_results.hpp b/boost/xpressive/match_results.hpp new file mode 100644 index 0000000000..6e9516d1f9 --- /dev/null +++ b/boost/xpressive/match_results.hpp @@ -0,0 +1,1395 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file match_results.hpp +/// Contains the definition of the match_results type and associated helpers. +/// The match_results type holds the results of a regex_match() or +/// regex_search() operation. +// +// 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) +// +// Acknowledgements: Thanks to Markus Schoepflin for helping to track down +// a tricky formatting bug on HP Tru64, and to Steven Watanabe for suggesting +// the fix. + +#ifndef BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <map> +#include <string> +#include <vector> +#include <utility> +#include <iterator> +#include <typeinfo> +#include <algorithm> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/integer.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/not.hpp> +#include <boost/mpl/size_t.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/iterator_adaptors.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/numeric/conversion/converter.hpp> +#include <boost/optional.hpp> +#include <boost/range/end.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/as_literal.hpp> +#include <boost/range/const_iterator.hpp> +#include <boost/type_traits/is_function.hpp> +#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 +# include <boost/iterator/filter_iterator.hpp> +#endif +#include <boost/xpressive/regex_constants.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/regex_impl.hpp> +#include <boost/xpressive/detail/core/sub_match_vector.hpp> +#include <boost/xpressive/detail/utility/sequence_stack.hpp> +#include <boost/xpressive/detail/core/results_cache.hpp> +#include <boost/xpressive/detail/utility/literals.hpp> +#include <boost/xpressive/detail/utility/algorithm.hpp> +#include <boost/xpressive/detail/utility/counted_base.hpp> +// Doxygen can't handle proto :-( +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# include <boost/proto/proto_fwd.hpp> +# include <boost/proto/traits.hpp> +#endif + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// type_info_less +// +struct type_info_less +{ + bool operator()(std::type_info const *left, std::type_info const *right) const + { + return 0 != left->before(*right); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ActionArgBinding +// +struct ActionArgBinding + : proto::assign<proto::terminal<action_arg<proto::_, proto::_> >, proto::terminal<proto::_> > +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// results_extras +// +template<typename BidiIter> +struct results_extras + : counted_base<results_extras<BidiIter> > +{ + sequence_stack<sub_match_impl<BidiIter> > sub_match_stack_; + results_cache<BidiIter> results_cache_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// char_overflow_handler_ +// +struct char_overflow_handler_ +{ + void operator ()(numeric::range_check_result result) const // throw(regex_error) + { + if(numeric::cInRange != result) + { + BOOST_THROW_EXCEPTION( + regex_error( + regex_constants::error_escape + , "character escape too large to fit in target character type" + ) + ); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// transform_op enum +// +enum transform_op { None = 0, Upper = 1, Lower = 2 }; +enum transform_scope { Next = 0, Rest = 1 }; + +/////////////////////////////////////////////////////////////////////////////// +// case_converting_iterator +// +template<typename OutputIterator, typename Char> +struct case_converting_iterator + : std::iterator<std::output_iterator_tag, Char, void, void, case_converting_iterator<OutputIterator, Char> > +{ + case_converting_iterator(OutputIterator const &out, traits<Char> const *tr) + : out_(out) + , traits_(tr) + , next_(None) + , rest_(None) + {} + + OutputIterator base() const + { + return this->out_; + } + + case_converting_iterator &operator ++() + { + ++this->out_; + this->next_ = None; + return *this; + } + + case_converting_iterator operator ++(int) + { + case_converting_iterator tmp(*this); + ++*this; + return tmp; + } + + case_converting_iterator &operator *() + { + return *this; + } + + friend bool set_transform(case_converting_iterator &iter, transform_op trans, transform_scope scope) + { + BOOST_ASSERT(scope == Next || scope == Rest); + if(scope == Next) + iter.next_ = trans; + else + iter.rest_ = trans; + return true; + } + + case_converting_iterator &operator =(Char ch) + { + switch(this->next_ ? this->next_ : this->rest_) + { + case Lower: + ch = this->traits_->tolower(ch); + break; + + case Upper: + ch = this->traits_->toupper(ch); + break; + + default:; + } + + *this->out_ = ch; + return *this; + } + +private: + OutputIterator out_; + traits<Char> const *traits_; + transform_op next_, rest_; +}; + +template<typename Iterator> +inline bool set_transform(Iterator &, transform_op, transform_scope) +{ + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// noop_output_iterator +// +template<typename Char> +struct noop_output_iterator + : std::iterator<std::output_iterator_tag, Char, void, void, noop_output_iterator<Char> > +{ + noop_output_iterator &operator ++() + { + return *this; + } + + noop_output_iterator &operator ++(int) + { + return *this; + } + + noop_output_iterator &operator *() + { + return *this; + } + + noop_output_iterator &operator =(Char const &) + { + return *this; + } +}; + +struct any_type { any_type(...); }; +typedef char no_type; +typedef char (&unary_type)[2]; +typedef char (&binary_type)[3]; +typedef char (&ternary_type)[4]; + +no_type check_is_formatter(unary_type, binary_type, ternary_type); + +template<typename T> +unary_type check_is_formatter(T const &, binary_type, ternary_type); + +template<typename T> +binary_type check_is_formatter(unary_type, T const &, ternary_type); + +template<typename T, typename U> +binary_type check_is_formatter(T const &, U const &, ternary_type); + +template<typename T> +ternary_type check_is_formatter(unary_type, binary_type, T const &); + +template<typename T, typename U> +ternary_type check_is_formatter(T const &, binary_type, U const &); + +template<typename T, typename U> +ternary_type check_is_formatter(unary_type, T const &, U const &); + +template<typename T, typename U, typename V> +ternary_type check_is_formatter(T const &, U const &, V const &); + +struct unary_binary_ternary +{ + typedef unary_type (*unary_fun)(any_type); + typedef binary_type (*binary_fun)(any_type, any_type); + typedef ternary_type (*ternary_fun)(any_type, any_type, any_type); + operator unary_fun(); + operator binary_fun(); + operator ternary_fun(); +}; + +template<typename Formatter, bool IsFunction = is_function<Formatter>::value> +struct formatter_wrapper + : Formatter + , unary_binary_ternary +{ + formatter_wrapper(); +}; + +template<typename Formatter> +struct formatter_wrapper<Formatter, true> + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template<typename Formatter> +struct formatter_wrapper<Formatter *, false> + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template<typename Formatter, typename What, typename Out, typename Void = void> +struct formatter_arity +{ + static formatter_wrapper<Formatter> &formatter; + static What &what; + static Out &out; + BOOST_STATIC_CONSTANT( + std::size_t + , value = sizeof( + check_is_formatter( + formatter(what) + , formatter(what, out) + , formatter(what, out, regex_constants::format_default) + ) + ) - 1 + ); + typedef mpl::size_t<value> type; +}; + +template<typename Formatter, typename What, typename Out> +struct formatter_arity<Formatter, What, Out, typename Formatter::proto_is_expr_> + : mpl::size_t<4> +{}; + +template<typename T> +struct is_char_ptr + : mpl::false_ +{}; + +template<typename T> +struct is_char_ptr<T *> + : mpl::not_<is_function<T> > +{}; + +#if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) +// work around gcc-4.0.1 compiler bug wrt function references +template<typename T> +typename mpl::if_<is_function<T>, T *, T const &>::type +as_callable(T const &t) +{ + return t; +} +#endif + +} // detail + +/////////////////////////////////////////////////////////////////////////////// +// match_results +/// \brief Class template match_results\<\> holds the results of a regex_match() or a +/// regex_search() as a collection of sub_match objects. +/// +/// Class template match_results\<\> denotes a collection of sequences representing the result of +/// a regular expression match. Storage for the collection is allocated and freed as necessary by +/// the member functions of class match_results\<\>. +/// +/// The class template match_results\<\> conforms to the requirements of a Sequence, as specified +/// in (lib.sequence.reqmts), except that only operations defined for const-qualified Sequences are +/// supported. +template<typename BidiIter> +struct match_results +{ +private: + /// INTERNAL ONLY + /// + struct dummy { int i_; }; + typedef int dummy::*bool_type; + +public: + typedef typename iterator_value<BidiIter>::type char_type; + typedef typename detail::string_type<char_type>::type string_type; + typedef std::size_t size_type; + typedef sub_match<BidiIter> value_type; + typedef typename iterator_difference<BidiIter>::type difference_type; + typedef value_type const &reference; + typedef value_type const &const_reference; + + typedef typename detail::sub_match_vector<BidiIter>::iterator iterator; + typedef typename detail::sub_match_vector<BidiIter>::const_iterator const_iterator; + typedef typename detail::nested_results<BidiIter> nested_results_type; + + /// \post regex_id() == 0 + /// \post size() == 0 + /// \post empty() == true + /// \post str() == string_type() + match_results() + : regex_id_(0) + , sub_matches_() + , base_() + , prefix_() + , suffix_() + , nested_results_() + , extras_ptr_() + , traits_() + , args_() + , named_marks_() + { + } + + /// \param that The match_results object to copy + /// \post regex_id() == that.regex_id(). + /// \post size() == that.size(). + /// \post empty() == that.empty(). + /// \post str(n) == that.str(n) for all positive integers n \< that.size(). + /// \post prefix() == that.prefix(). + /// \post suffix() == that.suffix(). + /// \post (*this)[n] == that[n] for all positive integers n \< that.size(). + /// \post length(n) == that.length(n) for all positive integers n \< that.size(). + /// \post position(n) == that.position(n) for all positive integers n \< that.size(). + match_results(match_results<BidiIter> const &that) + : regex_id_(that.regex_id_) + , sub_matches_() + , base_() + , prefix_() + , suffix_() + , nested_results_() + , extras_ptr_() + , traits_() + , args_(that.args_) + , named_marks_(that.named_marks_) + { + if(that) + { + extras_type &extras = this->get_extras_(); + std::size_t size = that.sub_matches_.size(); + detail::sub_match_impl<BidiIter> *sub_matches = extras.sub_match_stack_.push_sequence(size, detail::sub_match_impl<BidiIter>(*that.base_), detail::fill); + detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size, that.sub_matches_); + + this->base_ = that.base_; + this->prefix_ = that.prefix_; + this->suffix_ = that.suffix_; + // BUGBUG this doesn't share the extras::sequence_stack + this->nested_results_ = that.nested_results_; + this->traits_ = that.traits_; + } + } + + ~match_results() + { + } + + /// \param that The match_results object to copy. + /// \post regex_id() == that.regex_id(). + /// \post size() == that.size(). + /// \post empty() == that.empty(). + /// \post str(n) == that.str(n) for all positive integers n \< that.size(). + /// \post prefix() == that.prefix(). + /// \post suffix() == that.suffix(). + /// \post (*this)[n] == that[n] for all positive integers n \< that.size(). + /// \post length(n) == that.length(n) for all positive integers n \< that.size(). + /// \post position(n) == that.position(n) for all positive integers n \< that.size(). + match_results<BidiIter> &operator =(match_results<BidiIter> const &that) + { + match_results<BidiIter>(that).swap(*this); + return *this; + } + + /// Returns one plus the number of marked sub-expressions in the regular + /// expression that was matched if *this represents the result of a + /// successful match. Otherwise returns 0. + size_type size() const + { + return this->sub_matches_.size(); + } + + /// Returns size() == 0. + /// + bool empty() const + { + return 0 == this->size(); + } + + /// Returns (*this)[sub].length(). + /// + difference_type length(size_type sub = 0) const + { + return this->sub_matches_[ sub ].length(); + } + + /// If !(*this)[sub].matched then returns -1. Otherwise returns std::distance(base, (*this)[sub].first), + /// where base is the start iterator of the sequence that was searched. [Note - unless this is part + /// of a repeated search with a regex_iterator then base is the same as prefix().first - end note] + difference_type position(size_type sub = 0) const + { + return this->sub_matches_[ sub ].matched ? std::distance(*this->base_, this->sub_matches_[ sub ].first) : -1; + } + + /// Returns (*this)[sub].str(). + /// + string_type str(size_type sub = 0) const + { + return this->sub_matches_[ sub ].str(); + } + + /// Returns a reference to the sub_match object representing the sequence that + /// matched marked sub-expression sub. If sub == 0 then returns a reference to + /// a sub_match object representing the sequence that matched the whole regular + /// expression. If sub >= size() then returns a sub_match object representing an + /// unmatched sub-expression. + template<typename Sub> + const_reference operator [](Sub const &sub) const + { + return this->at_(sub); + } + + /// Returns a reference to the sub_match object representing the character sequence from + /// the start of the string being matched/searched, to the start of the match found. + /// + /// \pre (*this)[0].matched is true + const_reference prefix() const + { + return this->prefix_ ? *this->prefix_ : this->sub_matches_[this->sub_matches_.size()]; + } + + /// Returns a reference to the sub_match object representing the character sequence from + /// the end of the match found to the end of the string being matched/searched. + /// + /// \pre (*this)[0].matched is true + const_reference suffix() const + { + return this->suffix_ ? *this->suffix_ : this->sub_matches_[this->sub_matches_.size()]; + } + + /// Returns a starting iterator that enumerates over all the marked sub-expression matches + /// stored in *this. + /// + const_iterator begin() const + { + return this->sub_matches_.begin(); + } + + /// Returns a terminating iterator that enumerates over all the marked sub-expression + /// matches stored in *this. + /// + const_iterator end() const + { + return this->sub_matches_.end(); + } + + /// Returns a true value if (*this)[0].matched, else returns a false value. + /// + operator bool_type() const + { + return (!this->empty() && this->sub_matches_[ 0 ].matched) ? &dummy::i_ : 0; + } + + /// Returns true if empty() || !(*this)[0].matched, else returns false. + /// + bool operator !() const + { + return this->empty() || !this->sub_matches_[ 0 ].matched; + } + + /// Returns the id of the basic_regex object most recently used with this match_results object. + /// + regex_id_type regex_id() const + { + return this->regex_id_; + } + + /// Returns a Sequence of nested match_results elements. + /// + nested_results_type const &nested_results() const + { + return this->nested_results_; + } + + /// If \c Format models \c ForwardRange or is a null-terminated string, this function + /// copies the character sequence in \c fmt to \c OutputIterator \c out. For each format + /// specifier or escape sequence in \c fmt, replace that sequence with either the character(s) it + /// represents, or the sequence within <tt>*this</tt> to which it refers. The bitmasks specified in flags + /// determines what format specifiers or escape sequences are recognized. By default, this is the + /// format used by ECMA-262, ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator, regex_constants::match_flag_type\></tt>, + /// this function returns <tt>fmt(*this, out, flags)</tt>. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator\></tt>, this function + /// returns <tt>fmt(*this, out)</tt>. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\> \></tt>, this function + /// returns <tt>std::copy(x.begin(), x.end(), out)</tt>, where \c x is the result of + /// calling <tt>fmt(*this)</tt>. + template<typename Format, typename OutputIterator> + OutputIterator format + ( + OutputIterator out + , Format const &fmt + , regex_constants::match_flag_type flags = regex_constants::format_default + , typename disable_if<detail::is_char_ptr<Format> >::type * = 0 + ) const + { + // Is this a formatter object, or a format string? + typedef + typename detail::formatter_arity< + Format + , match_results<BidiIter> + , OutputIterator + >::type + arity; + + return this->format_(out, fmt, flags, arity()); + } + + /// \overload + /// + template<typename OutputIterator> + OutputIterator format + ( + OutputIterator out + , char_type const *fmt + , regex_constants::match_flag_type flags = regex_constants::format_default + ) const + { + return this->format_(out, boost::as_literal(fmt), flags, mpl::size_t<0>()); + } + + /// If \c Format models \c ForwardRange or is a null-terminated string, this function + /// returns a copy of the character sequence \c fmt. For each format specifier or escape sequence in \c fmt, + /// replace that sequence with either the character(s) it represents, or the sequence within + /// <tt>*this</tt> to which it refers. The bitmasks specified in \c flags determines what format specifiers + /// or escape sequences are recognized. By default this is the format used by ECMA-262, + /// ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator, regex_constants::match_flag_type\></tt>, + /// this function returns a \c string_type object \c x populated by calling <tt>fmt(*this, out, flags)</tt>, + /// where \c out is a \c back_insert_iterator into \c x. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator\></tt>, this function + /// returns a \c string_type object \c x populated by calling <tt>fmt(*this, out)</tt>, + /// where \c out is a \c back_insert_iterator into \c x. + /// + /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\> \></tt>, this function + /// returns <tt>fmt(*this)</tt>. + template<typename Format, typename OutputIterator> + string_type format + ( + Format const &fmt + , regex_constants::match_flag_type flags = regex_constants::format_default + , typename disable_if<detail::is_char_ptr<Format> >::type * = 0 + ) const + { + string_type result; + this->format(std::back_inserter(result), fmt, flags); + return result; + } + + /// \overload + /// + string_type format + ( + char_type const *fmt + , regex_constants::match_flag_type flags = regex_constants::format_default + ) const + { + string_type result; + this->format(std::back_inserter(result), fmt, flags); + return result; + } + + /// Swaps the contents of two match_results objects. Guaranteed not to throw. + /// \param that The match_results object to swap with. + /// \post *this contains the sequence of matched sub-expressions that were in that, + /// that contains the sequence of matched sub-expressions that were in *this. + /// \throw nothrow + void swap(match_results<BidiIter> &that) // throw() + { + using std::swap; + swap(this->regex_id_, that.regex_id_); + this->sub_matches_.swap(that.sub_matches_); + this->base_.swap(that.base_); + this->prefix_.swap(that.prefix_); + this->suffix_.swap(that.suffix_); + this->nested_results_.swap(that.nested_results_); + this->extras_ptr_.swap(that.extras_ptr_); + this->traits_.swap(that.traits_); + this->args_.swap(that.args_); + } + + /// TODO document me + /// + template<typename Arg> + match_results<BidiIter> &let(Arg const &arg) + { + typedef typename proto::result_of::left<Arg>::type left_type; + typedef typename proto::result_of::right<Arg>::type right_type; + typedef typename proto::result_of::value<left_type>::type arg_left_type; + typedef typename proto::result_of::value<right_type>::type arg_right_type; + BOOST_MPL_ASSERT((proto::matches<Arg, detail::ActionArgBinding>)); + BOOST_MPL_ASSERT((is_same<typename arg_left_type::type, arg_right_type>)); + this->args_[&typeid(proto::value(proto::left(arg)))] = &proto::value(proto::right(arg)); + return *this; + } + + /// INTERNAL ONLY + /// + match_results<BidiIter> const &operator ()(regex_id_type regex_id, size_type index = 0) const + { + // BUGBUG this is linear, make it O(1) + static match_results<BidiIter> const s_null; + + regex_id_filter_predicate<BidiIter> pred(regex_id); + typename nested_results_type::const_iterator + begin = this->nested_results_.begin() + , end = this->nested_results_.end() + , cur = detail::find_nth_if(begin, end, index, pred); + + return (cur == end) ? s_null : *cur; + } + + /// INTERNAL ONLY + /// + match_results<BidiIter> const &operator ()(basic_regex<BidiIter> const &rex, std::size_t index = 0) const + { + return (*this)(rex.regex_id(), index); + } + +private: + + friend struct detail::core_access<BidiIter>; + typedef detail::results_extras<BidiIter> extras_type; + + /// INTERNAL ONLY + /// + void init_ + ( + regex_id_type regex_id + , intrusive_ptr<detail::traits<char_type> const> const &tr + , detail::sub_match_impl<BidiIter> *sub_matches + , size_type size + , std::vector<detail::named_mark<char_type> > const &named_marks + ) + { + this->traits_ = tr; + this->regex_id_ = regex_id; + this->named_marks_ = named_marks; + detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size); + } + + /// INTERNAL ONLY + /// + extras_type &get_extras_() + { + if(!this->extras_ptr_) + { + this->extras_ptr_ = new extras_type; + } + + return *this->extras_ptr_; + } + + /// INTERNAL ONLY + /// + void set_prefix_suffix_(BidiIter begin, BidiIter end) + { + this->base_ = begin; + this->prefix_ = sub_match<BidiIter>(begin, this->sub_matches_[ 0 ].first, begin != this->sub_matches_[ 0 ].first); + this->suffix_ = sub_match<BidiIter>(this->sub_matches_[ 0 ].second, end, this->sub_matches_[ 0 ].second != end); + + typename nested_results_type::iterator ibegin = this->nested_results_.begin(); + typename nested_results_type::iterator iend = this->nested_results_.end(); + for( ; ibegin != iend; ++ibegin ) + { + ibegin->set_prefix_suffix_(begin, end); + } + } + + /// INTERNAL ONLY + /// + void reset_() + { + detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, 0, 0); + } + + /// INTERNAL ONLY + /// + void set_base_(BidiIter base) + { + this->base_ = base; + + typename nested_results_type::iterator ibegin = this->nested_results_.begin(); + typename nested_results_type::iterator iend = this->nested_results_.end(); + for( ; ibegin != iend; ++ibegin ) + { + ibegin->set_base_(base); + } + } + + /// INTERNAL ONLY + /// + const_reference at_(size_type sub) const + { + return this->sub_matches_[ sub ]; + } + + /// INTERNAL ONLY + /// + const_reference at_(detail::basic_mark_tag const &mark) const + { + return this->sub_matches_[ detail::get_mark_number(mark) ]; + } + + /// INTERNAL ONLY + /// + const_reference at_(char_type const *name) const + { + for(std::size_t i = 0; i < this->named_marks_.size(); ++i) + { + if(this->named_marks_[i].name_ == name) + { + return this->sub_matches_[ this->named_marks_[i].mark_nbr_ ]; + } + } + BOOST_THROW_EXCEPTION( + regex_error(regex_constants::error_badmark, "invalid named back-reference") + ); + // Should never execute, but if it does, this returns + // a "null" sub_match. + return this->sub_matches_[this->sub_matches_.size()]; + } + + /// INTERNAL ONLY + /// + const_reference at_(string_type const &name) const + { + return (*this)[name.c_str()]; + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename ForwardRange> + OutputIterator format2_(OutputIterator out, ForwardRange const &result) const + { + return std::copy(boost::begin(result), boost::end(result), out); + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename Char> + OutputIterator format2_(OutputIterator out, Char const *const &result) const + { + Char const *tmp = result; + BOOST_ASSERT(0 != tmp); + for(; 0 != *tmp; ++tmp, ++out) + { + *out = *tmp; + } + return out; + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename ForwardRange> + OutputIterator format_ + ( + OutputIterator out + , ForwardRange const &format + , regex_constants::match_flag_type flags + , mpl::size_t<0> + ) const + { + typedef typename range_const_iterator<ForwardRange>::type iterator; + iterator cur = boost::begin(format), end = boost::end(format); + + if(0 != (regex_constants::format_literal & flags)) + { + return std::copy(cur, end, out); + } + else if(0 != (regex_constants::format_perl & flags)) + { + return this->format_perl_(cur, end, out); + } + else if(0 != (regex_constants::format_sed & flags)) + { + return this->format_sed_(cur, end, out); + } + else if(0 != (regex_constants::format_all & flags)) + { + return this->format_all_(cur, end, out); + } + + return this->format_ecma_262_(cur, end, out); + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename Callable1> + OutputIterator format_ + ( + OutputIterator out + , Callable1 const &format + , regex_constants::match_flag_type + , mpl::size_t<1> + ) const + { + #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) + return this->format2_(out, detail::as_callable(format)(*this)); + #else + return this->format2_(out, format(*this)); + #endif + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename Callable2> + OutputIterator format_ + ( + OutputIterator out + , Callable2 const &format + , regex_constants::match_flag_type + , mpl::size_t<2> + ) const + { + #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) + return detail::as_callable(format)(*this, out); + #else + return format(*this, out); + #endif + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename Callable3> + OutputIterator format_ + ( + OutputIterator out + , Callable3 const &format + , regex_constants::match_flag_type flags + , mpl::size_t<3> + ) const + { + #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) + return detail::as_callable(format)(*this, out, flags); + #else + return format(*this, out, flags); + #endif + } + + /// INTERNAL ONLY + /// + template<typename OutputIterator, typename Expr> + OutputIterator format_ + ( + OutputIterator out + , Expr const &format + , regex_constants::match_flag_type flags + , mpl::size_t<4> + ) const + { + // detail::ReplaceAlgo may be an incomplete type at this point, so + // we can't construct it directly. + typedef typename mpl::if_c<true, detail::ReplaceAlgo, OutputIterator>::type ReplaceAlgo; + return this->format2_(out, ReplaceAlgo()(format, 0, *this)); + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_ecma_262_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const + { + while(cur != end) + { + switch(*cur) + { + case BOOST_XPR_CHAR_(char_type, '$'): + out = this->format_backref_(++cur, end, out); + break; + + default: + *out++ = *cur++; + break; + } + } + + return out; + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_sed_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const + { + while(cur != end) + { + switch(*cur) + { + case BOOST_XPR_CHAR_(char_type, '&'): + ++cur; + out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out); + break; + + case BOOST_XPR_CHAR_(char_type, '\\'): + out = this->format_escape_(++cur, end, out); + break; + + default: + *out++ = *cur++; + break; + } + } + + return out; + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_perl_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const + { + detail::case_converting_iterator<OutputIterator, char_type> iout(out, this->traits_.get()); + + while(cur != end) + { + switch(*cur) + { + case BOOST_XPR_CHAR_(char_type, '$'): + iout = this->format_backref_(++cur, end, iout); + break; + + case BOOST_XPR_CHAR_(char_type, '\\'): + if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur) + { + iout = this->format_named_backref_(++cur, end, iout); + } + else + { + iout = this->format_escape_(cur, end, iout); + } + break; + + default: + *iout++ = *cur++; + break; + } + } + + return iout.base(); + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_all_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const + { + detail::case_converting_iterator<OutputIterator, char_type> iout(out, this->traits_.get()); + iout = this->format_all_impl_(cur, end, iout); + BOOST_XPR_ENSURE_(cur == end + , regex_constants::error_paren, "unbalanced parentheses in format string"); + return iout.base(); + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_all_impl_(ForwardIterator &cur, ForwardIterator end, OutputIterator out, bool metacolon = false) const + { + int max = 0, sub = 0; + detail::noop_output_iterator<char_type> noop; + + while(cur != end) + { + switch(*cur) + { + case BOOST_XPR_CHAR_(char_type, '$'): + out = this->format_backref_(++cur, end, out); + break; + + case BOOST_XPR_CHAR_(char_type, '\\'): + if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur) + { + out = this->format_named_backref_(++cur, end, out); + } + else + { + out = this->format_escape_(cur, end, out); + } + break; + + case BOOST_XPR_CHAR_(char_type, '('): + out = this->format_all_impl_(++cur, end, out); + BOOST_XPR_ENSURE_(BOOST_XPR_CHAR_(char_type, ')') == *(cur-1) + , regex_constants::error_paren, "unbalanced parentheses in format string"); + break; + + case BOOST_XPR_CHAR_(char_type, '?'): + BOOST_XPR_ENSURE_(++cur != end + , regex_constants::error_subreg, "malformed conditional in format string"); + max = static_cast<int>(this->size() - 1); + sub = detail::toi(cur, end, *this->traits_, 10, max); + BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference"); + if(this->sub_matches_[ sub ].matched) + { + out = this->format_all_impl_(cur, end, out, true); + if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1)) + this->format_all_impl_(cur, end, noop); + } + else + { + this->format_all_impl_(cur, end, noop, true); + if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1)) + out = this->format_all_impl_(cur, end, out); + } + return out; + + case BOOST_XPR_CHAR_(char_type, ':'): + if(metacolon) + { + case BOOST_XPR_CHAR_(char_type, ')'): + ++cur; + return out; + } + // else fall-through + + default: + *out++ = *cur++; + break; + } + } + + return out; + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_backref_ + ( + ForwardIterator &cur + , ForwardIterator end + , OutputIterator out + ) const + { + if(cur == end) + { + *out++ = BOOST_XPR_CHAR_(char_type, '$'); + } + else if(BOOST_XPR_CHAR_(char_type, '$') == *cur) + { + *out++ = *cur++; + } + else if(BOOST_XPR_CHAR_(char_type, '&') == *cur) // whole match + { + ++cur; + out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out); + } + else if(BOOST_XPR_CHAR_(char_type, '`') == *cur) // prefix + { + ++cur; + out = std::copy(this->prefix().first, this->prefix().second, out); + } + else if(BOOST_XPR_CHAR_(char_type, '\'') == *cur) // suffix + { + ++cur; + out = std::copy(this->suffix().first, this->suffix().second, out); + } + else if(-1 != this->traits_->value(*cur, 10)) // a sub-match + { + int max = static_cast<int>(this->size() - 1); + int sub = detail::toi(cur, end, *this->traits_, 10, max); + BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference"); + if(this->sub_matches_[ sub ].matched) + out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); + } + else + { + *out++ = BOOST_XPR_CHAR_(char_type, '$'); + *out++ = *cur++; + } + + return out; + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_escape_ + ( + ForwardIterator &cur + , ForwardIterator end + , OutputIterator out + ) const + { + using namespace regex_constants; + ForwardIterator tmp; + // define an unsigned type the same size as char_type + typedef typename boost::uint_t<CHAR_BIT * sizeof(char_type)>::least uchar_t; + BOOST_MPL_ASSERT_RELATION(sizeof(uchar_t), ==, sizeof(char_type)); + typedef numeric::conversion_traits<uchar_t, int> converstion_traits; + numeric::converter<int, uchar_t, converstion_traits, detail::char_overflow_handler_> converter; + + if(cur == end) + { + *out++ = BOOST_XPR_CHAR_(char_type, '\\'); + return out; + } + + char_type ch = *cur++; + switch(ch) + { + case BOOST_XPR_CHAR_(char_type, 'a'): + *out++ = BOOST_XPR_CHAR_(char_type, '\a'); + break; + + case BOOST_XPR_CHAR_(char_type, 'e'): + *out++ = converter(27); + break; + + case BOOST_XPR_CHAR_(char_type, 'f'): + *out++ = BOOST_XPR_CHAR_(char_type, '\f'); + break; + + case BOOST_XPR_CHAR_(char_type, 'n'): + *out++ = BOOST_XPR_CHAR_(char_type, '\n'); + break; + + case BOOST_XPR_CHAR_(char_type, 'r'): + *out++ = BOOST_XPR_CHAR_(char_type, '\r'); + break; + + case BOOST_XPR_CHAR_(char_type, 't'): + *out++ = BOOST_XPR_CHAR_(char_type, '\t'); + break; + + case BOOST_XPR_CHAR_(char_type, 'v'): + *out++ = BOOST_XPR_CHAR_(char_type, '\v'); + break; + + case BOOST_XPR_CHAR_(char_type, 'x'): + BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found"); + if(BOOST_XPR_CHAR_(char_type, '{') == *cur) + { + BOOST_XPR_ENSURE_(++cur != end, error_escape, "unexpected end of format found"); + tmp = cur; + *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xffff)); + BOOST_XPR_ENSURE_(4 == std::distance(tmp, cur) && cur != end && BOOST_XPR_CHAR_(char_type, '}') == *cur++ + , error_escape, "invalid hex escape : must be \\x { HexDigit HexDigit HexDigit HexDigit }"); + } + else + { + tmp = cur; + *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xff)); + BOOST_XPR_ENSURE_(2 == std::distance(tmp, cur), error_escape + , "invalid hex escape : must be \\x HexDigit HexDigit"); + } + break; + + case BOOST_XPR_CHAR_(char_type, 'c'): + BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found"); + BOOST_XPR_ENSURE_ + ( + this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'a'), BOOST_XPR_CHAR_(char_type, 'z'), *cur) + || this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'A'), BOOST_XPR_CHAR_(char_type, 'Z'), *cur) + , error_escape + , "invalid escape control letter; must be one of a-z or A-Z" + ); + // Convert to character according to ECMA-262, section 15.10.2.10: + *out++ = converter(*cur % 32); + ++cur; + break; + + case BOOST_XPR_CHAR_(char_type, 'l'): + if(!set_transform(out, detail::Lower, detail::Next)) + { + *out++ = BOOST_XPR_CHAR_(char_type, 'l'); + } + break; + + case BOOST_XPR_CHAR_(char_type, 'L'): + if(!set_transform(out, detail::Lower, detail::Rest)) + { + *out++ = BOOST_XPR_CHAR_(char_type, 'L'); + } + break; + + case BOOST_XPR_CHAR_(char_type, 'u'): + if(!set_transform(out, detail::Upper, detail::Next)) + { + *out++ = BOOST_XPR_CHAR_(char_type, 'u'); + } + break; + + case BOOST_XPR_CHAR_(char_type, 'U'): + if(!set_transform(out, detail::Upper, detail::Rest)) + { + *out++ = BOOST_XPR_CHAR_(char_type, 'U'); + } + break; + + case BOOST_XPR_CHAR_(char_type, 'E'): + if(!set_transform(out, detail::None, detail::Rest)) + { + *out++ = BOOST_XPR_CHAR_(char_type, 'E'); + } + break; + + default: + // BUGBUG what about backreferences like \12 ? + if(0 < this->traits_->value(ch, 10)) + { + int sub = this->traits_->value(ch, 10); + if(this->sub_matches_[ sub ].matched) + out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); + } + else + { + *out++ = ch; + } + break; + } + + return out; + } + + /// INTERNAL ONLY + /// + template<typename ForwardIterator, typename OutputIterator> + OutputIterator format_named_backref_ + ( + ForwardIterator &cur + , ForwardIterator end + , OutputIterator out + ) const + { + using namespace regex_constants; + BOOST_XPR_ENSURE_(cur != end && BOOST_XPR_CHAR_(char_type, '<') == *cur++ + , error_badmark, "invalid named back-reference"); + ForwardIterator begin = cur; + for(; cur != end && BOOST_XPR_CHAR_(char_type, '>') != *cur; ++cur) + {} + BOOST_XPR_ENSURE_(cur != begin && cur != end && BOOST_XPR_CHAR_(char_type, '>') == *cur + , error_badmark, "invalid named back-reference"); + + string_type name(begin, cur++); + for(std::size_t i = 0; i < this->named_marks_.size(); ++i) + { + if(this->named_marks_[i].name_ == name) + { + std::size_t sub = this->named_marks_[i].mark_nbr_; + return std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); + } + } + + BOOST_THROW_EXCEPTION(regex_error(error_badmark, "invalid named back-reference")); + // Should never get here + return out; + } + + regex_id_type regex_id_; + detail::sub_match_vector<BidiIter> sub_matches_; + boost::optional<BidiIter> base_; + boost::optional<sub_match<BidiIter> > prefix_; + boost::optional<sub_match<BidiIter> > suffix_; + nested_results_type nested_results_; + intrusive_ptr<extras_type> extras_ptr_; + intrusive_ptr<detail::traits<char_type> const> traits_; + detail::action_args_type args_; + std::vector<detail::named_mark<char_type> > named_marks_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// regex_id_filter_predicate +// +template<typename BidiIter> +struct regex_id_filter_predicate + : std::unary_function<match_results<BidiIter>, bool> +{ + regex_id_filter_predicate(regex_id_type regex_id) + : regex_id_(regex_id) + { + } + + bool operator ()(match_results<BidiIter> const &res) const + { + return this->regex_id_ == res.regex_id(); + } + +private: + + regex_id_type regex_id_; +}; + +}} // namespace boost::xpressive + +#ifdef BOOST_HAS_CONCEPTS +// Better living through concepts. :-P +namespace std +{ + template<typename Iter_, typename Char_> + concept_map OutputIterator< + boost::xpressive::detail::case_converting_iterator<Iter_, Char_> + , Char_ + > + {}; + + template<typename Char_> + concept_map OutputIterator< + boost::xpressive::detail::noop_output_iterator<Char_> + , Char_ + > + {}; +} +#endif + +#endif diff --git a/boost/xpressive/regex_actions.hpp b/boost/xpressive/regex_actions.hpp new file mode 100644 index 0000000000..e22b164a88 --- /dev/null +++ b/boost/xpressive/regex_actions.hpp @@ -0,0 +1,973 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_actions.hpp +/// Defines the syntax elements of xpressive's action expressions. +// +// 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_ACTIONS_HPP_EAN_03_22_2007 +#define BOOST_XPRESSIVE_ACTIONS_HPP_EAN_03_22_2007 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/preprocessor/punctuation/comma_if.hpp> +#include <boost/ref.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/int.hpp> +#include <boost/noncopyable.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/throw_exception.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/core/matcher/attr_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/attr_end_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/attr_begin_matcher.hpp> +#include <boost/xpressive/detail/core/matcher/predicate_matcher.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +// These are very often needed by client code. +#include <boost/typeof/std/map.hpp> +#include <boost/typeof/std/string.hpp> + +// Doxygen can't handle proto :-( +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# include <boost/proto/core.hpp> +# include <boost/proto/transform.hpp> +# include <boost/xpressive/detail/core/matcher/action_matcher.hpp> +#endif + +/// INTERNAL ONLY +/// +#define UNREF(x) typename remove_reference<x>::type + +/// INTERNAL ONLY +/// +#define UNCVREF(x) typename remove_cv<typename remove_reference<x>::type>::type + +#if BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4510) // default constructor could not be generated +#pragma warning(disable : 4512) // assignment operator could not be generated +#pragma warning(disable : 4610) // can never be instantiated - user defined constructor required +#endif + +namespace boost +{ + namespace detail + { + // Bit of a hack to make lexical_cast work with wide sub_match + template<typename T> + struct stream_char; + + template<typename BidiIter> + struct stream_char<xpressive::sub_match<BidiIter> > + : boost::iterator_value<BidiIter> + {}; + } +} + +namespace boost { namespace xpressive +{ + + namespace detail + { + template<typename T, typename U> + struct action_arg + { + typedef T type; + typedef typename add_reference<T>::type reference; + + reference cast(void *pv) const + { + return *static_cast<UNREF(T) *>(pv); + } + }; + + template<typename T> + struct value_wrapper + : private noncopyable + { + value_wrapper() + : value() + {} + + value_wrapper(T const &t) + : value(t) + {} + + T value; + }; + + struct check_tag + {}; + + struct BindArg + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result; + + template<typename This, typename MatchResults, typename Expr> + struct result<This(MatchResults, Expr)> + { + typedef Expr type; + }; + + template<typename MatchResults, typename Expr> + Expr const & operator ()(MatchResults &what, Expr const &expr) const + { + what.let(expr); + return expr; + } + }; + + struct let_tag + {}; + + // let(_a = b, _c = d) + struct BindArgs + : proto::function< + proto::terminal<let_tag> + , proto::vararg< + proto::when< + proto::assign<proto::_, proto::_> + , proto::call<BindArg(proto::_data, proto::_)> + > + > + > + {}; + + struct let_domain + : boost::proto::domain<boost::proto::pod_generator<let_> > + {}; + + template<typename Expr> + struct let_ + { + BOOST_PROTO_BASIC_EXTENDS(Expr, let_<Expr>, let_domain) + BOOST_PROTO_EXTENDS_FUNCTION() + }; + + template<typename Args, typename BidiIter> + void bind_args(let_<Args> const &args, match_results<BidiIter> &what) + { + BindArgs()(args, 0, what); + } + + typedef boost::proto::functional::make_expr<proto::tag::function, proto::default_domain> make_function; + } + + namespace op + { + struct at + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result; + + template<typename This, typename Cont, typename Idx> + struct result<This(Cont, Idx)> + : result<This(Cont const &, Idx)> + { + }; + + template<typename This, typename Cont, typename Idx> + struct result<This(Cont &, Idx)> + { + typedef typename Cont::reference type; + }; + + template<typename This, typename Cont, typename Idx> + struct result<This(Cont const &, Idx)> + { + typedef typename Cont::const_reference type; + }; + + template<typename Cont, typename Idx> + typename Cont::reference operator()(Cont &c, Idx idx BOOST_PROTO_DISABLE_IF_IS_CONST(Cont)) const + { + return c[idx]; + } + + template<typename Cont, typename Idx> + typename Cont::const_reference operator()(Cont const &c, Idx idx) const + { + return c[idx]; + } + }; + + struct push + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence, typename Value> + void operator()(Sequence &seq, Value const &val) const + { + seq.push(val); + } + }; + + struct push_back + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence, typename Value> + void operator()(Sequence &seq, Value const &val) const + { + seq.push_back(val); + } + }; + + struct push_front + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence, typename Value> + void operator()(Sequence &seq, Value const &val) const + { + seq.push_front(val); + } + }; + + struct pop + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence> + void operator()(Sequence &seq) const + { + seq.pop(); + } + }; + + struct pop_back + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence> + void operator()(Sequence &seq) const + { + seq.pop_back(); + } + }; + + struct pop_front + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + template<typename Sequence> + void operator()(Sequence &seq) const + { + seq.pop_front(); + } + }; + + struct front + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Sequence> + struct result<This(Sequence)> + { + typedef UNREF(Sequence) sequence_type; + typedef + typename mpl::if_c< + is_const<sequence_type>::value + , typename sequence_type::const_reference + , typename sequence_type::reference + >::type + type; + }; + + template<typename Sequence> + typename result<front(Sequence &)>::type operator()(Sequence &seq) const + { + return seq.front(); + } + }; + + struct back + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Sequence> + struct result<This(Sequence)> + { + typedef UNREF(Sequence) sequence_type; + typedef + typename mpl::if_c< + is_const<sequence_type>::value + , typename sequence_type::const_reference + , typename sequence_type::reference + >::type + type; + }; + + template<typename Sequence> + typename result<back(Sequence &)>::type operator()(Sequence &seq) const + { + return seq.back(); + } + }; + + struct top + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Sequence> + struct result<This(Sequence)> + { + typedef UNREF(Sequence) sequence_type; + typedef + typename mpl::if_c< + is_const<sequence_type>::value + , typename sequence_type::value_type const & + , typename sequence_type::value_type & + >::type + type; + }; + + template<typename Sequence> + typename result<top(Sequence &)>::type operator()(Sequence &seq) const + { + return seq.top(); + } + }; + + struct first + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Pair> + struct result<This(Pair)> + { + typedef UNREF(Pair)::first_type type; + }; + + template<typename Pair> + typename Pair::first_type operator()(Pair const &p) const + { + return p.first; + } + }; + + struct second + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Pair> + struct result<This(Pair)> + { + typedef UNREF(Pair)::second_type type; + }; + + template<typename Pair> + typename Pair::second_type operator()(Pair const &p) const + { + return p.second; + } + }; + + struct matched + { + BOOST_PROTO_CALLABLE() + typedef bool result_type; + + template<typename Sub> + bool operator()(Sub const &sub) const + { + return sub.matched; + } + }; + + struct length + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Sub> + struct result<This(Sub)> + { + typedef UNREF(Sub)::difference_type type; + }; + + template<typename Sub> + typename Sub::difference_type operator()(Sub const &sub) const + { + return sub.length(); + } + }; + + struct str + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename Sub> + struct result<This(Sub)> + { + typedef UNREF(Sub)::string_type type; + }; + + template<typename Sub> + typename Sub::string_type operator()(Sub const &sub) const + { + return sub.str(); + } + }; + + // This codifies the return types of the various insert member + // functions found in sequence containers, the 2 flavors of + // associative containers, and strings. + struct insert + { + BOOST_PROTO_CALLABLE() + template<typename Sig, typename EnableIf = void> + struct result + {}; + + // assoc containers + template<typename This, typename Cont, typename Value> + struct result<This(Cont, Value), void> + { + typedef UNREF(Cont) cont_type; + typedef UNREF(Value) value_type; + static cont_type &scont_; + static value_type &svalue_; + typedef char yes_type; + typedef char (&no_type)[2]; + static yes_type check_insert_return(typename cont_type::iterator); + static no_type check_insert_return(std::pair<typename cont_type::iterator, bool>); + BOOST_STATIC_CONSTANT(bool, is_iterator = (sizeof(yes_type) == sizeof(check_insert_return(scont_.insert(svalue_))))); + typedef + typename mpl::if_c< + is_iterator + , typename cont_type::iterator + , std::pair<typename cont_type::iterator, bool> + >::type + type; + }; + + // sequence containers, assoc containers, strings + template<typename This, typename Cont, typename It, typename Value> + struct result<This(Cont, It, Value), + typename disable_if<mpl::or_<is_integral<UNCVREF(It)>, is_same<UNCVREF(It), UNCVREF(Value)> > >::type> + { + typedef UNREF(Cont)::iterator type; + }; + + // strings + template<typename This, typename Cont, typename Size, typename T> + struct result<This(Cont, Size, T), + typename enable_if<is_integral<UNCVREF(Size)> >::type> + { + typedef UNREF(Cont) &type; + }; + + // assoc containers + template<typename This, typename Cont, typename It> + struct result<This(Cont, It, It), void> + { + typedef void type; + }; + + // sequence containers, strings + template<typename This, typename Cont, typename It, typename Size, typename Value> + struct result<This(Cont, It, Size, Value), + typename disable_if<is_integral<UNCVREF(It)> >::type> + { + typedef void type; + }; + + // strings + template<typename This, typename Cont, typename Size, typename A0, typename A1> + struct result<This(Cont, Size, A0, A1), + typename enable_if<is_integral<UNCVREF(Size)> >::type> + { + typedef UNREF(Cont) &type; + }; + + /// operator() + /// + template<typename Cont, typename A0> + typename result<insert(Cont &, A0 const &)>::type + operator()(Cont &cont, A0 const &a0) const + { + return cont.insert(a0); + } + + /// \overload + /// + template<typename Cont, typename A0, typename A1> + typename result<insert(Cont &, A0 const &, A1 const &)>::type + operator()(Cont &cont, A0 const &a0, A1 const &a1) const + { + return cont.insert(a0, a1); + } + + /// \overload + /// + template<typename Cont, typename A0, typename A1, typename A2> + typename result<insert(Cont &, A0 const &, A1 const &, A2 const &)>::type + operator()(Cont &cont, A0 const &a0, A1 const &a1, A2 const &a2) const + { + return cont.insert(a0, a1, a2); + } + }; + + struct make_pair + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result {}; + + template<typename This, typename First, typename Second> + struct result<This(First, Second)> + { + typedef std::pair<UNCVREF(First), UNCVREF(Second)> type; + }; + + template<typename First, typename Second> + std::pair<First, Second> operator()(First const &first, Second const &second) const + { + return std::make_pair(first, second); + } + }; + + template<typename T> + struct as + { + BOOST_PROTO_CALLABLE() + typedef T result_type; + + template<typename Value> + T operator()(Value const &val) const + { + return lexical_cast<T>(val); + } + }; + + template<typename T> + struct static_cast_ + { + BOOST_PROTO_CALLABLE() + typedef T result_type; + + template<typename Value> + T operator()(Value const &val) const + { + return static_cast<T>(val); + } + }; + + template<typename T> + struct dynamic_cast_ + { + BOOST_PROTO_CALLABLE() + typedef T result_type; + + template<typename Value> + T operator()(Value const &val) const + { + return dynamic_cast<T>(val); + } + }; + + template<typename T> + struct const_cast_ + { + BOOST_PROTO_CALLABLE() + typedef T result_type; + + template<typename Value> + T operator()(Value const &val) const + { + return const_cast<T>(val); + } + }; + + template<typename T> + struct construct + { + BOOST_PROTO_CALLABLE() + typedef T result_type; + + T operator()() const + { + return T(); + } + + template<typename A0> + T operator()(A0 const &a0) const + { + return T(a0); + } + + template<typename A0, typename A1> + T operator()(A0 const &a0, A1 const &a1) const + { + return T(a0, a1); + } + + template<typename A0, typename A1, typename A2> + T operator()(A0 const &a0, A1 const &a1, A2 const &a2) const + { + return T(a0, a1, a2); + } + }; + + template<typename Except> + struct throw_ + { + BOOST_PROTO_CALLABLE() + typedef void result_type; + + void operator()() const + { + BOOST_THROW_EXCEPTION(Except()); + } + + template<typename A0> + void operator()(A0 const &a0) const + { + BOOST_THROW_EXCEPTION(Except(a0)); + } + + template<typename A0, typename A1> + void operator()(A0 const &a0, A1 const &a1) const + { + BOOST_THROW_EXCEPTION(Except(a0, a1)); + } + + template<typename A0, typename A1, typename A2> + void operator()(A0 const &a0, A1 const &a1, A2 const &a2) const + { + BOOST_THROW_EXCEPTION(Except(a0, a1, a2)); + } + }; + + struct unwrap_reference + { + BOOST_PROTO_CALLABLE() + template<typename Sig> + struct result; + + template<typename This, typename Ref> + struct result<This(Ref)> + { + typedef typename boost::unwrap_reference<Ref>::type &type; + }; + + template<typename This, typename Ref> + struct result<This(Ref &)> + { + typedef typename boost::unwrap_reference<Ref>::type &type; + }; + + template<typename T> + T &operator()(boost::reference_wrapper<T> r) const + { + return static_cast<T &>(r); + } + }; + } + + template<typename Fun> + struct function + { + typedef typename proto::terminal<Fun>::type type; + }; + + function<op::at>::type const at = {{}}; + function<op::push>::type const push = {{}}; + function<op::push_back>::type const push_back = {{}}; + function<op::push_front>::type const push_front = {{}}; + function<op::pop>::type const pop = {{}}; + function<op::pop_back>::type const pop_back = {{}}; + function<op::pop_front>::type const pop_front = {{}}; + function<op::top>::type const top = {{}}; + function<op::back>::type const back = {{}}; + function<op::front>::type const front = {{}}; + function<op::first>::type const first = {{}}; + function<op::second>::type const second = {{}}; + function<op::matched>::type const matched = {{}}; + function<op::length>::type const length = {{}}; + function<op::str>::type const str = {{}}; + function<op::insert>::type const insert = {{}}; + function<op::make_pair>::type const make_pair = {{}}; + function<op::unwrap_reference>::type const unwrap_reference = {{}}; + + template<typename T> + struct value + : proto::extends<typename proto::terminal<T>::type, value<T> > + { + typedef proto::extends<typename proto::terminal<T>::type, value<T> > base_type; + + value() + : base_type() + {} + + explicit value(T const &t) + : base_type(base_type::proto_base_expr::make(t)) + {} + + using base_type::operator =; + + T &get() + { + return proto::value(*this); + } + + T const &get() const + { + return proto::value(*this); + } + }; + + template<typename T> + struct reference + : proto::extends<typename proto::terminal<reference_wrapper<T> >::type, reference<T> > + { + typedef proto::extends<typename proto::terminal<reference_wrapper<T> >::type, reference<T> > base_type; + + explicit reference(T &t) + : base_type(base_type::proto_base_expr::make(boost::ref(t))) + {} + + using base_type::operator =; + + T &get() const + { + return proto::value(*this).get(); + } + }; + + template<typename T> + struct local + : detail::value_wrapper<T> + , proto::terminal<reference_wrapper<T> >::type + { + typedef typename proto::terminal<reference_wrapper<T> >::type base_type; + + local() + : detail::value_wrapper<T>() + , base_type(base_type::make(boost::ref(detail::value_wrapper<T>::value))) + {} + + explicit local(T const &t) + : detail::value_wrapper<T>(t) + , base_type(base_type::make(boost::ref(detail::value_wrapper<T>::value))) + {} + + using base_type::operator =; + + T &get() + { + return proto::value(*this); + } + + T const &get() const + { + return proto::value(*this); + } + }; + + /// as (a.k.a., lexical_cast) + /// + template<typename X2_0, typename A0> + typename detail::make_function::impl<op::as<X2_0> const, A0 const &>::result_type const + as(A0 const &a0) + { + return detail::make_function::impl<op::as<X2_0> const, A0 const &>()((op::as<X2_0>()), a0); + } + + /// static_cast_ + /// + template<typename X2_0, typename A0> + typename detail::make_function::impl<op::static_cast_<X2_0> const, A0 const &>::result_type const + static_cast_(A0 const &a0) + { + return detail::make_function::impl<op::static_cast_<X2_0> const, A0 const &>()((op::static_cast_<X2_0>()), a0); + } + + /// dynamic_cast_ + /// + template<typename X2_0, typename A0> + typename detail::make_function::impl<op::dynamic_cast_<X2_0> const, A0 const &>::result_type const + dynamic_cast_(A0 const &a0) + { + return detail::make_function::impl<op::dynamic_cast_<X2_0> const, A0 const &>()((op::dynamic_cast_<X2_0>()), a0); + } + + /// const_cast_ + /// + template<typename X2_0, typename A0> + typename detail::make_function::impl<op::const_cast_<X2_0> const, A0 const &>::result_type const + const_cast_(A0 const &a0) + { + return detail::make_function::impl<op::const_cast_<X2_0> const, A0 const &>()((op::const_cast_<X2_0>()), a0); + } + + /// val() + /// + template<typename T> + value<T> const val(T const &t) + { + return value<T>(t); + } + + /// ref() + /// + template<typename T> + reference<T> const ref(T &t) + { + return reference<T>(t); + } + + /// cref() + /// + template<typename T> + reference<T const> const cref(T const &t) + { + return reference<T const>(t); + } + + /// check(), for testing custom assertions + /// + proto::terminal<detail::check_tag>::type const check = {{}}; + + /// let(), for binding references to non-local variables + /// + detail::let_<proto::terminal<detail::let_tag>::type> const let = {{{}}}; + + /// placeholder<T>, for defining a placeholder to stand in fo + /// a variable of type T in a semantic action. + /// + template<typename T, int I, typename Dummy> + struct placeholder + { + typedef placeholder<T, I, Dummy> this_type; + typedef typename proto::terminal<detail::action_arg<T, mpl::int_<I> > >::type action_arg_type; + + BOOST_PROTO_EXTENDS(action_arg_type, this_type, proto::default_domain) + }; + + /// Usage: construct\<Type\>(arg1, arg2) + /// + /// Usage: throw_\<Exception\>(arg1, arg2) + /// + #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a)\ + \ + template<typename X2_0 BOOST_PP_COMMA_IF(N) typename_A(N)>\ + typename detail::make_function::impl<op::construct<X2_0> const BOOST_PP_COMMA_IF(N) A_const_ref(N)>::result_type const\ + construct(A_const_ref_a(N))\ + {\ + return detail::make_function::impl<op::construct<X2_0> const BOOST_PP_COMMA_IF(N) A_const_ref(N)>()((op::construct<X2_0>()) BOOST_PP_COMMA_IF(N) a(N));\ + }\ + \ + template<typename X2_0 BOOST_PP_COMMA_IF(N) typename_A(N)>\ + typename detail::make_function::impl<op::throw_<X2_0> const BOOST_PP_COMMA_IF(N) A_const_ref(N)>::result_type const\ + throw_(A_const_ref_a(N))\ + {\ + return detail::make_function::impl<op::throw_<X2_0> const BOOST_PP_COMMA_IF(N) A_const_ref(N)>()((op::throw_<X2_0>()) BOOST_PP_COMMA_IF(N) a(N));\ + }\ + /**/ + + #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a + #define BOOST_PROTO_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_ARITY)) + #include BOOST_PROTO_LOCAL_ITERATE() + + namespace detail + { + inline void ignore_unused_regex_actions() + { + detail::ignore_unused(xpressive::at); + detail::ignore_unused(xpressive::push); + detail::ignore_unused(xpressive::push_back); + detail::ignore_unused(xpressive::push_front); + detail::ignore_unused(xpressive::pop); + detail::ignore_unused(xpressive::pop_back); + detail::ignore_unused(xpressive::pop_front); + detail::ignore_unused(xpressive::top); + detail::ignore_unused(xpressive::back); + detail::ignore_unused(xpressive::front); + detail::ignore_unused(xpressive::first); + detail::ignore_unused(xpressive::second); + detail::ignore_unused(xpressive::matched); + detail::ignore_unused(xpressive::length); + detail::ignore_unused(xpressive::str); + detail::ignore_unused(xpressive::insert); + detail::ignore_unused(xpressive::make_pair); + detail::ignore_unused(xpressive::unwrap_reference); + detail::ignore_unused(xpressive::check); + detail::ignore_unused(xpressive::let); + } + + struct mark_nbr + { + BOOST_PROTO_CALLABLE() + typedef int result_type; + + int operator()(mark_placeholder m) const + { + return m.mark_number_; + } + }; + + struct ReplaceAlgo + : proto::or_< + proto::when< + proto::terminal<mark_placeholder> + , op::at(proto::_data, proto::call<mark_nbr(proto::_value)>) + > + , proto::when< + proto::terminal<any_matcher> + , op::at(proto::_data, proto::size_t<0>) + > + , proto::when< + proto::terminal<reference_wrapper<proto::_> > + , op::unwrap_reference(proto::_value) + > + , proto::_default<ReplaceAlgo> + > + {}; + } +}} + +#undef UNREF +#undef UNCVREF + +#if BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // BOOST_XPRESSIVE_ACTIONS_HPP_EAN_03_22_2007 diff --git a/boost/xpressive/regex_algorithms.hpp b/boost/xpressive/regex_algorithms.hpp new file mode 100644 index 0000000000..9e934c495e --- /dev/null +++ b/boost/xpressive/regex_algorithms.hpp @@ -0,0 +1,994 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_algorithms.hpp +/// Contains the regex_match(), regex_search() and regex_replace() algorithms. +// +// 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_ALGORITHMS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_ALGORITHMS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <iterator> +#include <boost/mpl/or.hpp> +#include <boost/range/end.hpp> +#include <boost/range/begin.hpp> +#include <boost/mpl/identity.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/add_const.hpp> +#include <boost/type_traits/is_pointer.hpp> +#include <boost/type_traits/remove_const.hpp> +#include <boost/xpressive/match_results.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/state.hpp> +#include <boost/xpressive/detail/utility/save_restore.hpp> + +/// INTERNAL ONLY +/// +#define BOOST_XPR_NONDEDUCED_TYPE_(x) typename mpl::identity<x>::type + +namespace boost { namespace xpressive +{ + +/////////////////////////////////////////////////////////////////////////////// +// regex_match +/////////////////////////////////////////////////////////////////////////////// + +namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // regex_match_impl + template<typename BidiIter> + inline bool regex_match_impl + ( + BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + { + typedef detail::core_access<BidiIter> access; + BOOST_ASSERT(0 != re.regex_id()); + + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + state.flags_.match_all_ = true; + state.sub_match(0).begin_ = begin; + + if(access::match(re, state)) + { + access::set_prefix_suffix(what, begin, end); + return true; + } + + // handle partial matches + else if(state.found_partial_match_ && 0 != (flags & regex_constants::match_partial)) + { + state.set_partial_match(); + return true; + } + + access::reset(what); + return false; + } +} // namespace detail + +/// \brief See if a regex matches a sequence from beginning to end. +/// +/// Determines whether there is an exact match between the regular expression \c re, +/// and all of the sequence <tt>[begin, end)</tt>. +/// +/// \pre Type \c BidiIter meets the requirements of a Bidirectional Iterator (24.1.4). +/// \pre <tt>[begin,end)</tt> denotes a valid iterator range. +/// \param begin The beginning of the sequence. +/// \param end The end of the sequence. +/// \param what The \c match_results struct into which the sub_matches will be written +/// \param re The regular expression object to use +/// \param flags Optional match flags, used to control how the expression is matched +/// against the sequence. (See \c match_flag_type.) +/// \return \c true if a match is found, \c false otherwise +/// \throw regex_error on stack exhaustion +template<typename BidiIter> +inline bool regex_match +( + BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<BidiIter> access; + + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename BidiIter> +inline bool regex_match +( + BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename Char> +inline bool regex_match +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *begin + , match_results<Char *> &what + , basic_regex<Char *> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<Char *> access; + + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // BUGBUG this is inefficient + typedef typename remove_const<Char>::type char_type; + Char *end = begin + std::char_traits<char_type>::length(begin); + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_match +( + BidiRange &rng + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_match +( + BidiRange const &rng + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename Char> +inline bool regex_match +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *begin + , basic_regex<Char *> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<Char *> what; + typedef typename remove_const<Char>::type char_type; + Char *end = begin + std::char_traits<char_type>::length(begin); + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_match +( + BidiRange &rng + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + return detail::regex_match_impl(begin, end, what, re, flags); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_match +( + BidiRange const &rng + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + return detail::regex_match_impl(begin, end, what, re, flags); +} + + +/////////////////////////////////////////////////////////////////////////////// +// regex_search +/////////////////////////////////////////////////////////////////////////////// + +namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // regex_search_impl + template<typename BidiIter> + inline bool regex_search_impl + ( + match_state<BidiIter> &state + , basic_regex<BidiIter> const &re + , bool not_initial_null = false + ) + { + typedef core_access<BidiIter> access; + typedef typename iterator_value<BidiIter>::type char_type; + match_results<BidiIter> &what = *state.context_.results_ptr_; + BOOST_ASSERT(0 != re.regex_id()); + + bool const partial_ok = state.flags_.match_partial_; + save_restore<bool> not_null(state.flags_.match_not_null_, state.flags_.match_not_null_ || not_initial_null); + state.flags_.match_prev_avail_ = state.flags_.match_prev_avail_ || !state.bos(); + + regex_impl<BidiIter> const &impl = *access::get_regex_impl(re); + BidiIter const begin = state.cur_, end = state.end_; + BidiIter &sub0begin = state.sub_match(0).begin_; + sub0begin = state.cur_; + + // If match_continuous is set, we only need to check for a match at the current position + if(state.flags_.match_continuous_) + { + if(access::match(re, state)) + { + access::set_prefix_suffix(what, begin, end); + return true; + } + + // handle partial matches + else if(partial_ok && state.found_partial_match_) + { + state.set_partial_match(); + return true; + } + } + + // If we have a finder, use it to find where a potential match can start + else if(impl.finder_ && (!partial_ok || impl.finder_->ok_for_partial_matches())) + { + finder<BidiIter> const &find = *impl.finder_; + if(find(state)) + { + if(state.cur_ != begin) + { + not_null.restore(); + } + + do + { + sub0begin = state.cur_; + if(access::match(re, state)) + { + access::set_prefix_suffix(what, begin, end); + return true; + } + + // handle partial matches + else if(partial_ok && state.found_partial_match_) + { + state.set_partial_match(); + return true; + } + + BOOST_ASSERT(state.cur_ == sub0begin); + not_null.restore(); + } + while(state.cur_ != state.end_ && (++state.cur_, find(state))); + } + } + + // Otherwise, use brute force search at every position. + else + { + for(;;) + { + if(access::match(re, state)) + { + access::set_prefix_suffix(what, begin, end); + return true; + } + + // handle partial matches + else if(partial_ok && state.found_partial_match_) + { + state.set_partial_match(); + return true; + } + + else if(end == sub0begin) + { + break; + } + + BOOST_ASSERT(state.cur_ == sub0begin); + state.cur_ = ++sub0begin; + not_null.restore(); + } + } + + access::reset(what); + return false; + } +} // namespace detail + + +/// \brief Determines whether there is some sub-sequence within <tt>[begin,end)</tt> +/// that matches the regular expression \c re. +/// +/// Determines whether there is some sub-sequence within <tt>[begin,end)</tt> that matches +/// the regular expression \c re. +/// +/// \pre Type \c BidiIter meets the requirements of a Bidirectional Iterator (24.1.4). +/// \pre <tt>[begin,end)</tt> denotes a valid iterator range. +/// \param begin The beginning of the sequence +/// \param end The end of the sequence +/// \param what The \c match_results struct into which the sub_matches will be written +/// \param re The regular expression object to use +/// \param flags Optional match flags, used to control how the expression is matched against +/// the sequence. (See \c match_flag_type.) +/// \return \c true if a match is found, \c false otherwise +/// \throw regex_error on stack exhaustion +template<typename BidiIter> +inline bool regex_search +( + BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename BidiIter> +inline bool regex_search +( + BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename Char> +inline bool regex_search +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *begin + , match_results<Char *> &what + , basic_regex<Char *> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<Char *> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // BUGBUG this is inefficient + typedef typename remove_const<Char>::type char_type; + Char *end = begin + std::char_traits<char_type>::length(begin); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<Char *> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_search +( + BidiRange &rng + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_search +( + BidiRange const &rng + , match_results<BidiIter> &what + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + access::reset(what); + return false; + } + + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename Char> +inline bool regex_search +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *begin + , basic_regex<Char *> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef detail::core_access<Char *> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<Char *> what; + // BUGBUG this is inefficient + typedef typename remove_const<Char>::type char_type; + Char *end = begin + std::char_traits<char_type>::length(begin); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<Char *> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_search +( + BidiRange &rng + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + +/// \overload +/// +template<typename BidiRange, typename BidiIter> +inline bool regex_search +( + BidiRange const &rng + , basic_regex<BidiIter> const &re + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiRange> >::type * = 0 +) +{ + typedef detail::core_access<BidiIter> access; + + // a default-constructed regex matches nothing + if(0 == re.regex_id()) + { + return false; + } + + // BUGBUG this is inefficient + match_results<BidiIter> what; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(rng), end = boost::end(rng); + // the state object holds matching state and + // is passed by reference to all the matchers + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + return detail::regex_search_impl(state, re); +} + + +/////////////////////////////////////////////////////////////////////////////// +// regex_replace +/////////////////////////////////////////////////////////////////////////////// + +namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // regex_replace_impl + template<typename OutIter, typename BidiIter, typename Formatter> + inline OutIter regex_replace_impl + ( + OutIter out + , BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &re + , Formatter const &format + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + { + using namespace regex_constants; + typedef detail::core_access<BidiIter> access; + BOOST_ASSERT(0 != re.regex_id()); + + BidiIter cur = begin; + match_results<BidiIter> what; + detail::match_state<BidiIter> state(begin, end, what, *access::get_regex_impl(re), flags); + bool const yes_copy = (0 == (flags & format_no_copy)); + + if(detail::regex_search_impl(state, re)) + { + if(yes_copy) + { + out = std::copy(cur, what[0].first, out); + } + + out = what.format(out, format, flags); + cur = state.cur_ = state.next_search_ = what[0].second; + + if(0 == (flags & format_first_only)) + { + bool not_null = (0 == what.length()); + state.reset(what, *access::get_regex_impl(re)); + while(detail::regex_search_impl(state, re, not_null)) + { + if(yes_copy) + { + out = std::copy(cur, what[0].first, out); + } + + access::set_prefix_suffix(what, begin, end); + out = what.format(out, format, flags); + cur = state.cur_ = state.next_search_ = what[0].second; + not_null = (0 == what.length()); + state.reset(what, *access::get_regex_impl(re)); + } + } + } + + if(yes_copy) + { + out = std::copy(cur, end, out); + } + + return out; + } +} // namespace detail + +/// \brief Build an output sequence given an input sequence, a regex, and a format string or +/// a formatter object, function, or expression. +/// +/// Constructs a \c regex_iterator object: <tt>regex_iterator\< BidiIter \> i(begin, end, re, flags)</tt>, +/// and uses \c i to enumerate through all of the matches m of type <tt>match_results\< BidiIter \></tt> that +/// occur within the sequence <tt>[begin, end)</tt>. If no such matches are found and <tt>!(flags \& format_no_copy)</tt> +/// then calls <tt>std::copy(begin, end, out)</tt>. Otherwise, for each match found, if <tt>!(flags \& format_no_copy)</tt> +/// calls <tt>std::copy(m.prefix().first, m.prefix().second, out)</tt>, and then calls <tt>m.format(out, format, flags)</tt>. +/// Finally if <tt>!(flags \& format_no_copy)</tt> calls <tt>std::copy(last_m.suffix().first, last_m.suffix().second, out)</tt> +/// where \c last_m is a copy of the last match found. +/// +/// If <tt>flags \& format_first_only</tt> is non-zero then only the first match found is replaced. +/// +/// \pre Type \c BidiIter meets the requirements of a Bidirectional Iterator (24.1.4). +/// \pre Type \c OutIter meets the requirements of an Output Iterator (24.1.2). +/// \pre Type \c Formatter models \c ForwardRange, <tt>Callable\<match_results\<BidiIter\> \></tt>, +/// <tt>Callable\<match_results\<BidiIter\>, OutIter\></tt>, or +/// <tt>Callable\<match_results\<BidiIter\>, OutIter, regex_constants::match_flag_type\></tt>; +/// or else it is a null-terminated format string, or an expression template +/// representing a formatter lambda expression. +/// \pre <tt>[begin,end)</tt> denotes a valid iterator range. +/// \param out An output iterator into which the output sequence is written. +/// \param begin The beginning of the input sequence. +/// \param end The end of the input sequence. +/// \param re The regular expression object to use. +/// \param format The format string used to format the replacement sequence, +/// or a formatter function, function object, or expression. +/// \param flags Optional match flags, used to control how the expression is matched against +/// the sequence. (See \c match_flag_type.) +/// \return The value of the output iterator after the output sequence has been written to it. +/// \throw regex_error on stack exhaustion or invalid format string. +template<typename OutIter, typename BidiIter, typename Formatter> +inline OutIter regex_replace +( + OutIter out + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , basic_regex<BidiIter> const &re + , Formatter const &format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<Formatter> >::type * = 0 +) +{ + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + out = std::copy(begin, end, out); + } + + return out; + } + + return detail::regex_replace_impl(out, begin, end, re, format, flags); +} + +/// \overload +/// +template<typename OutIter, typename BidiIter> +inline OutIter regex_replace +( + OutIter out + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) begin + , BOOST_XPR_NONDEDUCED_TYPE_(BidiIter) end + , basic_regex<BidiIter> const &re + , typename iterator_value<BidiIter>::type const *format + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + out = std::copy(begin, end, out); + } + + return out; + } + + return detail::regex_replace_impl(out, begin, end, re, format, flags); +} + +/// \overload +/// +template<typename BidiContainer, typename BidiIter, typename Formatter> +inline BidiContainer regex_replace +( + BidiContainer &str + , basic_regex<BidiIter> const &re + , Formatter const &format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<mpl::or_<detail::is_char_ptr<BidiContainer>, detail::is_char_ptr<Formatter> > >::type * = 0 +) +{ + BidiContainer result; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(str), end = boost::end(str); + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + std::copy(begin, end, std::back_inserter(result)); + } + + return result; + } + + detail::regex_replace_impl(std::back_inserter(result), begin, end, re, format, flags); + return result; +} + +/// \overload +/// +template<typename BidiContainer, typename BidiIter, typename Formatter> +inline BidiContainer regex_replace +( + BidiContainer const &str + , basic_regex<BidiIter> const &re + , Formatter const &format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<mpl::or_<detail::is_char_ptr<BidiContainer>, detail::is_char_ptr<Formatter> > >::type * = 0 +) +{ + BidiContainer result; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(str), end = boost::end(str); + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + std::copy(begin, end, std::back_inserter(result)); + } + + return result; + } + + detail::regex_replace_impl(std::back_inserter(result), begin, end, re, format, flags); + return result; +} + +/// \overload +/// +template<typename Char, typename Formatter> +inline std::basic_string<typename remove_const<Char>::type> regex_replace +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *str + , basic_regex<Char *> const &re + , Formatter const &format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<Formatter> >::type * = 0 +) +{ + typedef typename remove_const<Char>::type char_type; + std::basic_string<char_type> result; + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + result = str; + } + + return result; + } + + Char *end = str + std::char_traits<char_type>::length(str); + detail::regex_replace_impl(std::back_inserter(result), str, end, re, format, flags); + return result; +} + +/// \overload +/// +template<typename BidiContainer, typename BidiIter> +inline BidiContainer regex_replace +( + BidiContainer &str + , basic_regex<BidiIter> const &re + , typename iterator_value<BidiIter>::type const *format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiContainer> >::type * = 0 +) +{ + BidiContainer result; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(str), end = boost::end(str); + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + std::copy(begin, end, std::back_inserter(result)); + } + + return result; + } + + detail::regex_replace_impl(std::back_inserter(result), begin, end, re, format, flags); + return result; +} + +/// \overload +/// +template<typename BidiContainer, typename BidiIter> +inline BidiContainer regex_replace +( + BidiContainer const &str + , basic_regex<BidiIter> const &re + , typename iterator_value<BidiIter>::type const *format + , regex_constants::match_flag_type flags = regex_constants::match_default + , typename disable_if<detail::is_char_ptr<BidiContainer> >::type * = 0 +) +{ + BidiContainer result; + // Note that the result iterator of the range must be convertible + // to BidiIter here. + BidiIter begin = boost::begin(str), end = boost::end(str); + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + std::copy(begin, end, std::back_inserter(result)); + } + + return result; + } + + detail::regex_replace_impl(std::back_inserter(result), begin, end, re, format, flags); + return result; +} + +/// \overload +/// +template<typename Char> +inline std::basic_string<typename remove_const<Char>::type> regex_replace +( + BOOST_XPR_NONDEDUCED_TYPE_(Char) *str + , basic_regex<Char *> const &re + , typename add_const<Char>::type *format + , regex_constants::match_flag_type flags = regex_constants::match_default +) +{ + typedef typename remove_const<Char>::type char_type; + std::basic_string<char_type> result; + + // Default-constructed regexes match nothing + if(0 == re.regex_id()) + { + if((0 == (flags & regex_constants::format_no_copy))) + { + result = str; + } + + return result; + } + + Char *end = str + std::char_traits<char_type>::length(str); + detail::regex_replace_impl(std::back_inserter(result), str, end, re, format, flags); + return result; +} + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_compiler.hpp b/boost/xpressive/regex_compiler.hpp new file mode 100644 index 0000000000..4a2a9d7436 --- /dev/null +++ b/boost/xpressive/regex_compiler.hpp @@ -0,0 +1,744 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_compiler.hpp +/// Contains the definition of regex_compiler, a factory for building regex objects +/// from strings. +// +// 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_REGEX_COMPILER_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_COMPILER_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <map> +#include <boost/assert.hpp> +#include <boost/next_prior.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/throw_exception.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/is_pointer.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/xpressive/basic_regex.hpp> +#include <boost/xpressive/detail/dynamic/parser.hpp> +#include <boost/xpressive/detail/dynamic/parse_charset.hpp> +#include <boost/xpressive/detail/dynamic/parser_enum.hpp> +#include <boost/xpressive/detail/dynamic/parser_traits.hpp> +#include <boost/xpressive/detail/core/linker.hpp> +#include <boost/xpressive/detail/core/optimize.hpp> + +namespace boost { namespace xpressive +{ + +/////////////////////////////////////////////////////////////////////////////// +// regex_compiler +// +/// \brief Class template regex_compiler is a factory for building basic_regex objects from a string. +/// +/// Class template regex_compiler is used to construct a basic_regex object from a string. The string +/// should contain a valid regular expression. You can imbue a regex_compiler object with a locale, +/// after which all basic_regex objects created with that regex_compiler object will use that locale. +/// After creating a regex_compiler object, and optionally imbueing it with a locale, you can call the +/// compile() method to construct a basic_regex object, passing it the string representing the regular +/// expression. You can call compile() multiple times on the same regex_compiler object. Two basic_regex +/// objects compiled from the same string will have different regex_id's. +template<typename BidiIter, typename RegexTraits, typename CompilerTraits> +struct regex_compiler +{ + typedef BidiIter iterator_type; + typedef typename iterator_value<BidiIter>::type char_type; + typedef regex_constants::syntax_option_type flag_type; + typedef RegexTraits traits_type; + typedef typename traits_type::string_type string_type; + typedef typename traits_type::locale_type locale_type; + typedef typename traits_type::char_class_type char_class_type; + + explicit regex_compiler(RegexTraits const &traits = RegexTraits()) + : mark_count_(0) + , hidden_mark_count_(0) + , traits_(traits) + , upper_(0) + , self_() + , rules_() + { + this->upper_ = lookup_classname(this->rxtraits(), "upper"); + } + + /////////////////////////////////////////////////////////////////////////// + // imbue + /// Specify the locale to be used by a regex_compiler. + /// + /// \param loc The locale that this regex_compiler should use. + /// \return The previous locale. + locale_type imbue(locale_type loc) + { + locale_type oldloc = this->traits_.imbue(loc); + this->upper_ = lookup_classname(this->rxtraits(), "upper"); + return oldloc; + } + + /////////////////////////////////////////////////////////////////////////// + // getloc + /// Get the locale used by a regex_compiler. + /// + /// \return The locale used by this regex_compiler. + locale_type getloc() const + { + return this->traits_.getloc(); + } + + /////////////////////////////////////////////////////////////////////////// + // compile + /// Builds a basic_regex object from a range of characters. + /// + /// \param begin The beginning of a range of characters representing the + /// regular expression to compile. + /// \param end The end of a range of characters representing the + /// regular expression to compile. + /// \param flags Optional bitmask that determines how the pat string is + /// interpreted. (See syntax_option_type.) + /// \return A basic_regex object corresponding to the regular expression + /// represented by the character range. + /// \pre InputIter is a model of the InputIterator concept. + /// \pre [begin,end) is a valid range. + /// \pre The range of characters specified by [begin,end) contains a + /// valid string-based representation of a regular expression. + /// \throw regex_error when the range of characters has invalid regular + /// expression syntax. + template<typename InputIter> + basic_regex<BidiIter> + compile(InputIter begin, InputIter end, flag_type flags = regex_constants::ECMAScript) + { + typedef typename iterator_category<InputIter>::type category; + return this->compile_(begin, end, flags, category()); + } + + /// \overload + /// + template<typename InputRange> + typename disable_if<is_pointer<InputRange>, basic_regex<BidiIter> >::type + compile(InputRange const &pat, flag_type flags = regex_constants::ECMAScript) + { + return this->compile(boost::begin(pat), boost::end(pat), flags); + } + + /// \overload + /// + basic_regex<BidiIter> + compile(char_type const *begin, flag_type flags = regex_constants::ECMAScript) + { + BOOST_ASSERT(0 != begin); + char_type const *end = begin + std::char_traits<char_type>::length(begin); + return this->compile(begin, end, flags); + } + + /// \overload + /// + basic_regex<BidiIter> compile(char_type const *begin, std::size_t size, flag_type flags) + { + BOOST_ASSERT(0 != begin); + char_type const *end = begin + size; + return this->compile(begin, end, flags); + } + + /////////////////////////////////////////////////////////////////////////// + // operator[] + /// Return a reference to the named regular expression. If no such named + /// regular expression exists, create a new regular expression and return + /// a reference to it. + /// + /// \param name A std::string containing the name of the regular expression. + /// \pre The string is not empty. + /// \throw bad_alloc on allocation failure. + basic_regex<BidiIter> &operator [](string_type const &name) + { + BOOST_ASSERT(!name.empty()); + return this->rules_[name]; + } + + /// \overload + /// + basic_regex<BidiIter> const &operator [](string_type const &name) const + { + BOOST_ASSERT(!name.empty()); + return this->rules_[name]; + } + +private: + + typedef detail::escape_value<char_type, char_class_type> escape_value; + typedef detail::alternate_matcher<detail::alternates_vector<BidiIter>, RegexTraits> alternate_matcher; + + /////////////////////////////////////////////////////////////////////////// + // compile_ + /// INTERNAL ONLY + template<typename FwdIter> + basic_regex<BidiIter> compile_(FwdIter begin, FwdIter end, flag_type flags, std::forward_iterator_tag) + { + BOOST_MPL_ASSERT((is_same<char_type, typename iterator_value<FwdIter>::type>)); + using namespace regex_constants; + this->reset(); + this->traits_.flags(flags); + + basic_regex<BidiIter> rextmp, *prex = &rextmp; + FwdIter tmp = begin; + + // Check if this regex is a named rule: + string_type name; + if(token_group_begin == this->traits_.get_token(tmp, end) && + BOOST_XPR_ENSURE_(tmp != end, error_paren, "mismatched parenthesis") && + token_rule_assign == this->traits_.get_group_type(tmp, end, name)) + { + begin = tmp; + BOOST_XPR_ENSURE_ + ( + begin != end && token_group_end == this->traits_.get_token(begin, end) + , error_paren + , "mismatched parenthesis" + ); + prex = &this->rules_[name]; + } + + this->self_ = detail::core_access<BidiIter>::get_regex_impl(*prex); + + // at the top level, a regex is a sequence of alternates + detail::sequence<BidiIter> seq = this->parse_alternates(begin, end); + BOOST_XPR_ENSURE_(begin == end, error_paren, "mismatched parenthesis"); + + // terminate the sequence + seq += detail::make_dynamic<BidiIter>(detail::end_matcher()); + + // bundle the regex information into a regex_impl object + detail::common_compile(seq.xpr().matchable(), *this->self_, this->rxtraits()); + + this->self_->traits_ = new detail::traits_holder<RegexTraits>(this->rxtraits()); + this->self_->mark_count_ = this->mark_count_; + this->self_->hidden_mark_count_ = this->hidden_mark_count_; + + // References changed, update dependencies. + this->self_->tracking_update(); + this->self_.reset(); + return *prex; + } + + /////////////////////////////////////////////////////////////////////////// + // compile_ + /// INTERNAL ONLY + template<typename InputIter> + basic_regex<BidiIter> compile_(InputIter begin, InputIter end, flag_type flags, std::input_iterator_tag) + { + string_type pat(begin, end); + return this->compile_(boost::begin(pat), boost::end(pat), flags, std::forward_iterator_tag()); + } + + /////////////////////////////////////////////////////////////////////////// + // reset + /// INTERNAL ONLY + void reset() + { + this->mark_count_ = 0; + this->hidden_mark_count_ = 0; + this->traits_.flags(regex_constants::ECMAScript); + } + + /////////////////////////////////////////////////////////////////////////// + // regex_traits + /// INTERNAL ONLY + traits_type &rxtraits() + { + return this->traits_.traits(); + } + + /////////////////////////////////////////////////////////////////////////// + // regex_traits + /// INTERNAL ONLY + traits_type const &rxtraits() const + { + return this->traits_.traits(); + } + + /////////////////////////////////////////////////////////////////////////// + // parse_alternates + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_alternates(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + int count = 0; + FwdIter tmp = begin; + detail::sequence<BidiIter> seq; + + do switch(++count) + { + case 1: + seq = this->parse_sequence(tmp, end); + break; + case 2: + seq = detail::make_dynamic<BidiIter>(alternate_matcher()) | seq; + // fall-through + default: + seq |= this->parse_sequence(tmp, end); + } + while((begin = tmp) != end && token_alternate == this->traits_.get_token(tmp, end)); + + return seq; + } + + /////////////////////////////////////////////////////////////////////////// + // parse_group + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_group(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + int mark_nbr = 0; + bool keeper = false; + bool lookahead = false; + bool lookbehind = false; + bool negative = false; + string_type name; + + detail::sequence<BidiIter> seq, seq_end; + FwdIter tmp = FwdIter(); + + syntax_option_type old_flags = this->traits_.flags(); + + switch(this->traits_.get_group_type(begin, end, name)) + { + case token_no_mark: + // Don't process empty groups like (?:) or (?i) + // BUGBUG this doesn't handle the degenerate (?:)+ correctly + if(token_group_end == this->traits_.get_token(tmp = begin, end)) + { + return this->parse_atom(begin = tmp, end); + } + break; + + case token_negative_lookahead: + negative = true; // fall-through + case token_positive_lookahead: + lookahead = true; + break; + + case token_negative_lookbehind: + negative = true; // fall-through + case token_positive_lookbehind: + lookbehind = true; + break; + + case token_independent_sub_expression: + keeper = true; + break; + + case token_comment: + while(BOOST_XPR_ENSURE_(begin != end, error_paren, "mismatched parenthesis")) + { + switch(this->traits_.get_token(begin, end)) + { + case token_group_end: return this->parse_atom(begin, end); + case token_escape: BOOST_XPR_ENSURE_(begin != end, error_escape, "incomplete escape sequence"); + case token_literal: ++begin; + default:; + } + } + break; + + case token_recurse: + BOOST_XPR_ENSURE_ + ( + begin != end && token_group_end == this->traits_.get_token(begin, end) + , error_paren + , "mismatched parenthesis" + ); + return detail::make_dynamic<BidiIter>(detail::regex_byref_matcher<BidiIter>(this->self_)); + + case token_rule_assign: + BOOST_THROW_EXCEPTION( + regex_error(error_badrule, "rule assignments must be at the front of the regex") + ); + break; + + case token_rule_ref: + { + typedef detail::core_access<BidiIter> access; + BOOST_XPR_ENSURE_ + ( + begin != end && token_group_end == this->traits_.get_token(begin, end) + , error_paren + , "mismatched parenthesis" + ); + basic_regex<BidiIter> &rex = this->rules_[name]; + shared_ptr<detail::regex_impl<BidiIter> > impl = access::get_regex_impl(rex); + this->self_->track_reference(*impl); + return detail::make_dynamic<BidiIter>(detail::regex_byref_matcher<BidiIter>(impl)); + } + + case token_named_mark: + mark_nbr = static_cast<int>(++this->mark_count_); + for(std::size_t i = 0; i < this->self_->named_marks_.size(); ++i) + { + BOOST_XPR_ENSURE_(this->self_->named_marks_[i].name_ != name, error_badmark, "named mark already exists"); + } + this->self_->named_marks_.push_back(detail::named_mark<char_type>(name, this->mark_count_)); + seq = detail::make_dynamic<BidiIter>(detail::mark_begin_matcher(mark_nbr)); + seq_end = detail::make_dynamic<BidiIter>(detail::mark_end_matcher(mark_nbr)); + break; + + case token_named_mark_ref: + BOOST_XPR_ENSURE_ + ( + begin != end && token_group_end == this->traits_.get_token(begin, end) + , error_paren + , "mismatched parenthesis" + ); + for(std::size_t i = 0; i < this->self_->named_marks_.size(); ++i) + { + if(this->self_->named_marks_[i].name_ == name) + { + mark_nbr = static_cast<int>(this->self_->named_marks_[i].mark_nbr_); + return detail::make_backref_xpression<BidiIter> + ( + mark_nbr, this->traits_.flags(), this->rxtraits() + ); + } + } + BOOST_THROW_EXCEPTION(regex_error(error_badmark, "invalid named back-reference")); + break; + + default: + mark_nbr = static_cast<int>(++this->mark_count_); + seq = detail::make_dynamic<BidiIter>(detail::mark_begin_matcher(mark_nbr)); + seq_end = detail::make_dynamic<BidiIter>(detail::mark_end_matcher(mark_nbr)); + break; + } + + // alternates + seq += this->parse_alternates(begin, end); + seq += seq_end; + BOOST_XPR_ENSURE_ + ( + begin != end && token_group_end == this->traits_.get_token(begin, end) + , error_paren + , "mismatched parenthesis" + ); + + typedef detail::shared_matchable<BidiIter> xpr_type; + if(lookahead) + { + seq += detail::make_independent_end_xpression<BidiIter>(seq.pure()); + detail::lookahead_matcher<xpr_type> lookahead(seq.xpr(), negative, seq.pure()); + seq = detail::make_dynamic<BidiIter>(lookahead); + } + else if(lookbehind) + { + seq += detail::make_independent_end_xpression<BidiIter>(seq.pure()); + detail::lookbehind_matcher<xpr_type> lookbehind(seq.xpr(), seq.width().value(), negative, seq.pure()); + seq = detail::make_dynamic<BidiIter>(lookbehind); + } + else if(keeper) // independent sub-expression + { + seq += detail::make_independent_end_xpression<BidiIter>(seq.pure()); + detail::keeper_matcher<xpr_type> keeper(seq.xpr(), seq.pure()); + seq = detail::make_dynamic<BidiIter>(keeper); + } + + // restore the modifiers + this->traits_.flags(old_flags); + return seq; + } + + /////////////////////////////////////////////////////////////////////////// + // parse_charset + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_charset(FwdIter &begin, FwdIter end) + { + detail::compound_charset<traits_type> chset; + + // call out to a helper to actually parse the character set + detail::parse_charset(begin, end, chset, this->traits_); + + return detail::make_charset_xpression<BidiIter> + ( + chset + , this->rxtraits() + , this->traits_.flags() + ); + } + + /////////////////////////////////////////////////////////////////////////// + // parse_atom + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_atom(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + escape_value esc = { 0, 0, 0, detail::escape_char }; + FwdIter old_begin = begin; + + switch(this->traits_.get_token(begin, end)) + { + case token_literal: + return detail::make_literal_xpression<BidiIter> + ( + this->parse_literal(begin, end), this->traits_.flags(), this->rxtraits() + ); + + case token_any: + return detail::make_any_xpression<BidiIter>(this->traits_.flags(), this->rxtraits()); + + case token_assert_begin_sequence: + return detail::make_dynamic<BidiIter>(detail::assert_bos_matcher()); + + case token_assert_end_sequence: + return detail::make_dynamic<BidiIter>(detail::assert_eos_matcher()); + + case token_assert_begin_line: + return detail::make_assert_begin_line<BidiIter>(this->traits_.flags(), this->rxtraits()); + + case token_assert_end_line: + return detail::make_assert_end_line<BidiIter>(this->traits_.flags(), this->rxtraits()); + + case token_assert_word_boundary: + return detail::make_assert_word<BidiIter>(detail::word_boundary<mpl::true_>(), this->rxtraits()); + + case token_assert_not_word_boundary: + return detail::make_assert_word<BidiIter>(detail::word_boundary<mpl::false_>(), this->rxtraits()); + + case token_assert_word_begin: + return detail::make_assert_word<BidiIter>(detail::word_begin(), this->rxtraits()); + + case token_assert_word_end: + return detail::make_assert_word<BidiIter>(detail::word_end(), this->rxtraits()); + + case token_escape: + esc = this->parse_escape(begin, end); + switch(esc.type_) + { + case detail::escape_mark: + return detail::make_backref_xpression<BidiIter> + ( + esc.mark_nbr_, this->traits_.flags(), this->rxtraits() + ); + case detail::escape_char: + return detail::make_char_xpression<BidiIter> + ( + esc.ch_, this->traits_.flags(), this->rxtraits() + ); + case detail::escape_class: + return detail::make_posix_charset_xpression<BidiIter> + ( + esc.class_ + , this->is_upper_(*begin++) + , this->traits_.flags() + , this->rxtraits() + ); + } + + case token_group_begin: + return this->parse_group(begin, end); + + case token_charset_begin: + return this->parse_charset(begin, end); + + case token_invalid_quantifier: + BOOST_THROW_EXCEPTION(regex_error(error_badrepeat, "quantifier not expected")); + break; + + case token_quote_meta_begin: + return detail::make_literal_xpression<BidiIter> + ( + this->parse_quote_meta(begin, end), this->traits_.flags(), this->rxtraits() + ); + + case token_quote_meta_end: + BOOST_THROW_EXCEPTION( + regex_error( + error_escape + , "found quote-meta end without corresponding quote-meta begin" + ) + ); + break; + + case token_end_of_pattern: + break; + + default: + begin = old_begin; + break; + } + + return detail::sequence<BidiIter>(); + } + + /////////////////////////////////////////////////////////////////////////// + // parse_quant + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_quant(FwdIter &begin, FwdIter end) + { + BOOST_ASSERT(begin != end); + detail::quant_spec spec = { 0, 0, false, &this->hidden_mark_count_ }; + detail::sequence<BidiIter> seq = this->parse_atom(begin, end); + + // BUGBUG this doesn't handle the degenerate (?:)+ correctly + if(!seq.empty() && begin != end && detail::quant_none != seq.quant()) + { + if(this->traits_.get_quant_spec(begin, end, spec)) + { + BOOST_ASSERT(spec.min_ <= spec.max_); + + if(0 == spec.max_) // quant {0,0} is degenerate -- matches nothing. + { + seq = this->parse_quant(begin, end); + } + else + { + seq.repeat(spec); + } + } + } + + return seq; + } + + /////////////////////////////////////////////////////////////////////////// + // parse_sequence + /// INTERNAL ONLY + template<typename FwdIter> + detail::sequence<BidiIter> parse_sequence(FwdIter &begin, FwdIter end) + { + detail::sequence<BidiIter> seq; + + while(begin != end) + { + detail::sequence<BidiIter> seq_quant = this->parse_quant(begin, end); + + // did we find a quantified atom? + if(seq_quant.empty()) + break; + + // chain it to the end of the xpression sequence + seq += seq_quant; + } + + return seq; + } + + /////////////////////////////////////////////////////////////////////////// + // parse_literal + // scan ahead looking for char literals to be globbed together into a string literal + /// INTERNAL ONLY + template<typename FwdIter> + string_type parse_literal(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + BOOST_ASSERT(begin != end); + BOOST_ASSERT(token_literal == this->traits_.get_token(begin, end)); + escape_value esc = { 0, 0, 0, detail::escape_char }; + string_type literal(1, *begin); + + for(FwdIter prev = begin, tmp = ++begin; begin != end; prev = begin, begin = tmp) + { + detail::quant_spec spec = { 0, 0, false, &this->hidden_mark_count_ }; + if(this->traits_.get_quant_spec(tmp, end, spec)) + { + if(literal.size() != 1) + { + begin = prev; + literal.erase(boost::prior(literal.end())); + } + return literal; + } + else switch(this->traits_.get_token(tmp, end)) + { + case token_escape: + esc = this->parse_escape(tmp, end); + if(detail::escape_char != esc.type_) return literal; + literal.insert(literal.end(), esc.ch_); + break; + case token_literal: + literal.insert(literal.end(), *tmp++); + break; + default: + return literal; + } + } + + return literal; + } + + /////////////////////////////////////////////////////////////////////////// + // parse_quote_meta + // scan ahead looking for char literals to be globbed together into a string literal + /// INTERNAL ONLY + template<typename FwdIter> + string_type parse_quote_meta(FwdIter &begin, FwdIter end) + { + using namespace regex_constants; + FwdIter old_begin = begin, old_end; + while(end != (old_end = begin)) + { + switch(this->traits_.get_token(begin, end)) + { + case token_quote_meta_end: return string_type(old_begin, old_end); + case token_escape: BOOST_XPR_ENSURE_(begin != end, error_escape, "incomplete escape sequence"); + case token_invalid_quantifier: + case token_literal: ++begin; + default:; + } + } + return string_type(old_begin, begin); + } + + /////////////////////////////////////////////////////////////////////////////// + // parse_escape + /// INTERNAL ONLY + template<typename FwdIter> + escape_value parse_escape(FwdIter &begin, FwdIter end) + { + BOOST_XPR_ENSURE_(begin != end, regex_constants::error_escape, "incomplete escape sequence"); + + // first, check to see if this can be a backreference + if(0 < this->rxtraits().value(*begin, 10)) + { + // Parse at most 3 decimal digits. + FwdIter tmp = begin; + int mark_nbr = detail::toi(tmp, end, this->rxtraits(), 10, 999); + + // If the resulting number could conceivably be a backref, then it is. + if(10 > mark_nbr || mark_nbr <= static_cast<int>(this->mark_count_)) + { + begin = tmp; + escape_value esc = {0, mark_nbr, 0, detail::escape_mark}; + return esc; + } + } + + // Not a backreference, defer to the parse_escape helper + return detail::parse_escape(begin, end, this->traits_); + } + + bool is_upper_(char_type ch) const + { + return 0 != this->upper_ && this->rxtraits().isctype(ch, this->upper_); + } + + std::size_t mark_count_; + std::size_t hidden_mark_count_; + CompilerTraits traits_; + typename RegexTraits::char_class_type upper_; + shared_ptr<detail::regex_impl<BidiIter> > self_; + std::map<string_type, basic_regex<BidiIter> > rules_; +}; + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_constants.hpp b/boost/xpressive/regex_constants.hpp new file mode 100644 index 0000000000..49be39bc88 --- /dev/null +++ b/boost/xpressive/regex_constants.hpp @@ -0,0 +1,294 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_constants.hpp +/// Contains definitions for the syntax_option_type, match_flag_type and +/// error_type enumerations. +// +// 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_REGEX_CONSTANTS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_CONSTANTS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/mpl/identity.hpp> + +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# define icase icase_ +#endif + +namespace boost { namespace xpressive { namespace regex_constants +{ + +/// Flags used to customize the regex syntax +/// +enum syntax_option_type +{ + // these flags are required: + + ECMAScript = 0, ///< Specifies that the grammar recognized by the regular expression + ///< engine uses its normal semantics: that is the same as that given + ///< in the ECMA-262, ECMAScript Language Specification, Chapter 15 + ///< part 10, RegExp (Regular Expression) Objects (FWD.1). + ///< + icase = 1 << 1, ///< Specifies that matching of regular expressions against a character + ///< container sequence shall be performed without regard to case. + ///< + nosubs = 1 << 2, ///< Specifies that when a regular expression is matched against a + ///< character container sequence, then no sub-expression matches are to + ///< be stored in the supplied match_results structure. + ///< + optimize = 1 << 3, ///< Specifies that the regular expression engine should pay more + ///< attention to the speed with which regular expressions are matched, + ///< and less to the speed with which regular expression objects are + ///< constructed. Otherwise it has no detectable effect on the program + ///< output. + ///< + collate = 1 << 4, ///< Specifies that character ranges of the form "[a-b]" should be + ///< locale sensitive. + ///< + + // These flags are optional. If the functionality is supported + // then the flags shall take these names. + + //basic = 1 << 5, ///< Specifies that the grammar recognized by the regular expression + // ///< engine is the same as that used by POSIX basic regular expressions + // ///< in IEEE Std 1003.1-2001, Portable Operating System Interface + // ///< (POSIX), Base Definitions and Headers, Section 9, Regular + // ///< Expressions (FWD.1). + // ///< + //extended = 1 << 6, ///< Specifies that the grammar recognized by the regular expression + // ///< engine is the same as that used by POSIX extended regular + // ///< expressions in IEEE Std 1003.1-2001, Portable Operating System + // ///< Interface (POSIX), Base Definitions and Headers, Section 9, + // ///< Regular Expressions (FWD.1). + // ///< + //awk = 1 << 7, ///< Specifies that the grammar recognized by the regular expression + // ///< engine is the same as that used by POSIX utility awk in IEEE Std + // ///< 1003.1-2001, Portable Operating System Interface (POSIX), Shells + // ///< and Utilities, Section 4, awk (FWD.1). + // ///< + //grep = 1 << 8, ///< Specifies that the grammar recognized by the regular expression + // ///< engine is the same as that used by POSIX utility grep in IEEE Std + // ///< 1003.1-2001, Portable Operating System Interface (POSIX), + // ///< Shells and Utilities, Section 4, Utilities, grep (FWD.1). + // ///< + //egrep = 1 << 9, ///< Specifies that the grammar recognized by the regular expression + // ///< engine is the same as that used by POSIX utility grep when given + // ///< the -E option in IEEE Std 1003.1-2001, Portable Operating System + // ///< Interface (POSIX), Shells and Utilities, Section 4, Utilities, + // ///< grep (FWD.1). + // ///< + + // these flags are specific to xpressive, and they help with perl compliance. + + single_line = 1 << 10, ///< Specifies that the ^ and \$ metacharacters DO NOT match at + ///< internal line breaks. Note that this is the opposite of the + ///< perl default. It is the inverse of perl's /m (multi-line) + ///< modifier. + ///< + not_dot_null = 1 << 11, ///< Specifies that the . metacharacter does not match the null + ///< character \\0. + ///< + not_dot_newline = 1 << 12, ///< Specifies that the . metacharacter does not match the + ///< newline character \\n. + ///< + ignore_white_space = 1 << 13 ///< Specifies that non-escaped white-space is not significant. + ///< +}; + +/// Flags used to customize the behavior of the regex algorithms +/// +enum match_flag_type +{ + match_default = 0, ///< Specifies that matching of regular expressions proceeds + ///< without any modification of the normal rules used in + ///< ECMA-262, ECMAScript Language Specification, Chapter 15 + ///< part 10, RegExp (Regular Expression) Objects (FWD.1) + ///< + match_not_bol = 1 << 1, ///< Specifies that the expression "^" should not be matched + ///< against the sub-sequence [first,first). + ///< + match_not_eol = 1 << 2, ///< Specifies that the expression "\$" should not be + ///< matched against the sub-sequence [last,last). + ///< + match_not_bow = 1 << 3, ///< Specifies that the expression "\\b" should not be + ///< matched against the sub-sequence [first,first). + ///< + match_not_eow = 1 << 4, ///< Specifies that the expression "\\b" should not be + ///< matched against the sub-sequence [last,last). + ///< + match_any = 1 << 7, ///< Specifies that if more than one match is possible then + ///< any match is an acceptable result. + ///< + match_not_null = 1 << 8, ///< Specifies that the expression can not be matched + ///< against an empty sequence. + ///< + match_continuous = 1 << 10, ///< Specifies that the expression must match a sub-sequence + ///< that begins at first. + ///< + match_partial = 1 << 11, ///< Specifies that if no match can be found, then it is + ///< acceptable to return a match [from, last) where + ///< from != last, if there exists some sequence of characters + ///< [from,to) of which [from,last) is a prefix, and which + ///< would result in a full match. + ///< + match_prev_avail = 1 << 12, ///< Specifies that --first is a valid iterator position, + ///< when this flag is set then the flags match_not_bol + ///< and match_not_bow are ignored by the regular expression + ///< algorithms (RE.7) and iterators (RE.8). + ///< + format_default = 0, ///< Specifies that when a regular expression match is to be + ///< replaced by a new string, that the new string is + ///< constructed using the rules used by the ECMAScript + ///< replace function in ECMA-262, ECMAScript Language + ///< Specification, Chapter 15 part 5.4.11 + ///< String.prototype.replace. (FWD.1). In addition during + ///< search and replace operations then all non-overlapping + ///< occurrences of the regular expression are located and + ///< replaced, and sections of the input that did not match + ///< the expression, are copied unchanged to the output + ///< string. + ///< + format_sed = 1 << 13, ///< Specifies that when a regular expression match is to be + ///< replaced by a new string, that the new string is + ///< constructed using the rules used by the Unix sed + ///< utility in IEEE Std 1003.1-2001, Portable Operating + ///< SystemInterface (POSIX), Shells and Utilities. + ///< + format_perl = 1 << 14, ///< Specifies that when a regular expression match is to be + ///< replaced by a new string, that the new string is + ///< constructed using an implementation defined superset + ///< of the rules used by the ECMAScript replace function in + ///< ECMA-262, ECMAScript Language Specification, Chapter 15 + ///< part 5.4.11 String.prototype.replace (FWD.1). + ///< + format_no_copy = 1 << 15, ///< When specified during a search and replace operation, + ///< then sections of the character container sequence being + ///< searched that do match the regular expression, are not + ///< copied to the output string. + ///< + format_first_only = 1 << 16, ///< When specified during a search and replace operation, + ///< then only the first occurrence of the regular + ///< expression is replaced. + ///< + format_literal = 1 << 17, ///< Treat the format string as a literal. + ///< + format_all = 1 << 18 ///< Specifies that all syntax extensions are enabled, + ///< including conditional (?ddexpression1:expression2) + ///< replacements. + ///< +}; + +/// Error codes used by the regex_error type +/// +enum error_type +{ + error_collate, ///< The expression contained an invalid collating element name. + ///< + error_ctype, ///< The expression contained an invalid character class name. + ///< + error_escape, ///< The expression contained an invalid escaped character, + ///< or a trailing escape. + ///< + error_subreg, ///< The expression contained an invalid back-reference. + ///< + error_brack, ///< The expression contained mismatched [ and ]. + ///< + error_paren, ///< The expression contained mismatched ( and ). + ///< + error_brace, ///< The expression contained mismatched { and }. + ///< + error_badbrace, ///< The expression contained an invalid range in a {} expression. + ///< + error_range, ///< The expression contained an invalid character range, for + ///< example [b-a]. + ///< + error_space, ///< There was insufficient memory to convert the expression into a + ///< finite state machine. + ///< + error_badrepeat, ///< One of *?+{ was not preceded by a valid regular expression. + ///< + error_complexity, ///< The complexity of an attempted match against a regular + ///< expression exceeded a pre-set level. + ///< + error_stack, ///< There was insufficient memory to determine whether the regular + ///< expression could match the specified character sequence. + ///< + error_badref, ///< An nested regex is uninitialized. + ///< + error_badmark, ///< An invalid use of a named capture. + ///< + error_badlookbehind, ///< An attempt to create a variable-width look-behind assertion + ///< was detected. + ///< + error_badrule, ///< An invalid use of a rule was detected. + ///< + error_badarg, ///< An argument to an action was unbound. + ///< + error_badattr, ///< Tried to read from an uninitialized attribute. + ///< + error_internal ///< An internal error has occurred. + ///< +}; + +/// INTERNAL ONLY +inline syntax_option_type operator &(syntax_option_type b1, syntax_option_type b2) +{ + return static_cast<syntax_option_type>( + static_cast<int>(b1) & static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline syntax_option_type operator |(syntax_option_type b1, syntax_option_type b2) +{ + return static_cast<syntax_option_type>(static_cast<int>(b1) | static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline syntax_option_type operator ^(syntax_option_type b1, syntax_option_type b2) +{ + return static_cast<syntax_option_type>(static_cast<int>(b1) ^ static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline syntax_option_type operator ~(syntax_option_type b) +{ + return static_cast<syntax_option_type>(~static_cast<int>(b)); +} + +/// INTERNAL ONLY +inline match_flag_type operator &(match_flag_type b1, match_flag_type b2) +{ + return static_cast<match_flag_type>(static_cast<int>(b1) & static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline match_flag_type operator |(match_flag_type b1, match_flag_type b2) +{ + return static_cast<match_flag_type>(static_cast<int>(b1) | static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline match_flag_type operator ^(match_flag_type b1, match_flag_type b2) +{ + return static_cast<match_flag_type>(static_cast<int>(b1) ^ static_cast<int>(b2)); +} + +/// INTERNAL ONLY +inline match_flag_type operator ~(match_flag_type b) +{ + return static_cast<match_flag_type>(~static_cast<int>(b)); +} + +}}} // namespace boost::xpressive::regex_constants + +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# undef icase +#endif + +#endif diff --git a/boost/xpressive/regex_error.hpp b/boost/xpressive/regex_error.hpp new file mode 100644 index 0000000000..77fd8cb872 --- /dev/null +++ b/boost/xpressive/regex_error.hpp @@ -0,0 +1,114 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_error.hpp +/// Contains the definition of the regex_error exception class. +// +// 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_REGEX_ERROR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_ERROR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <stdexcept> +#include <boost/throw_exception.hpp> +#include <boost/current_function.hpp> +#include <boost/exception/exception.hpp> +#include <boost/exception/info.hpp> +#include <boost/xpressive/regex_constants.hpp> + +//{{AFX_DOC_COMMENT +/////////////////////////////////////////////////////////////////////////////// +// This is a hack to get Doxygen to show the inheritance relation between +// regex_error and std::runtime_error. +#ifdef BOOST_XPRESSIVE_DOXYGEN_INVOKED +/// INTERNAL ONLY +namespace std +{ + /// INTERNAL ONLY + struct runtime_error {}; +} +#endif +//}}AFX_DOC_COMMENT + +namespace boost { namespace xpressive +{ + +//////////////////////////////////////////////////////////////////////////////// +// regex_error +// +/// \brief The class regex_error defines the type of objects thrown as +/// exceptions to report errors during the conversion from a string representing +/// a regular expression to a finite state machine. +struct regex_error + : std::runtime_error + , boost::exception +{ + /// Constructs an object of class regex_error. + /// \param code The error_type this regex_error represents. + /// \post code() == code + explicit regex_error(regex_constants::error_type code, char const *str = "") + : std::runtime_error(str) + , boost::exception() + , code_(code) + { + } + + /// Accessor for the error_type value + /// \return the error_type code passed to the constructor + /// \throw nothrow + regex_constants::error_type code() const + { + return this->code_; + } + + /// Destructor for class regex_error + /// \throw nothrow + virtual ~regex_error() throw() + {} + +private: + + regex_constants::error_type code_; +}; + +namespace detail +{ + inline bool ensure_( + bool cond + , regex_constants::error_type code + , char const *msg + , char const *fun + , char const *file + , unsigned long line + ) + { + if(!cond) + { + #ifndef BOOST_EXCEPTION_DISABLE + boost::throw_exception( + boost::xpressive::regex_error(code, msg) + << boost::throw_function(fun) + << boost::throw_file(file) + << boost::throw_line((int)line) + ); + #else + boost::throw_exception(boost::xpressive::regex_error(code, msg)); + #endif + } + return true; + } +} + +#define BOOST_XPR_ENSURE_(pred, code, msg) \ + boost::xpressive::detail::ensure_(pred, code, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) \ + /**/ + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_iterator.hpp b/boost/xpressive/regex_iterator.hpp new file mode 100644 index 0000000000..e577300006 --- /dev/null +++ b/boost/xpressive/regex_iterator.hpp @@ -0,0 +1,260 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_iterator.hpp +/// Contains the definition of the regex_iterator type, an STL-compatible iterator +/// for stepping through all the matches in a sequence. +// +// 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_REGEX_ITERATOR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_ITERATOR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/noncopyable.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/access.hpp> +#include <boost/xpressive/detail/utility/counted_base.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +////////////////////////////////////////////////////////////////////////// +// regex_iterator_impl +// +template<typename BidiIter> +struct regex_iterator_impl + : counted_base<regex_iterator_impl<BidiIter> > +{ + typedef detail::core_access<BidiIter> access; + + regex_iterator_impl + ( + BidiIter begin + , BidiIter cur + , BidiIter end + , BidiIter next_search + , basic_regex<BidiIter> const &rex + , regex_constants::match_flag_type flags + , bool not_null = false + ) + : rex_(rex) + , what_() + , state_(begin, end, what_, *access::get_regex_impl(rex_), flags) + , flags_(flags) + , not_null_(not_null) + { + this->state_.cur_ = cur; + this->state_.next_search_ = next_search; + } + + bool next() + { + this->state_.reset(this->what_, *access::get_regex_impl(this->rex_)); + if(!regex_search_impl(this->state_, this->rex_, this->not_null_)) + { + return false; + } + + // Report position() correctly by setting the base different from prefix().first + access::set_base(this->what_, this->state_.begin_); + + this->state_.cur_ = this->state_.next_search_ = this->what_[0].second; + this->not_null_ = (0 == this->what_.length()); + + return true; + } + + bool equal_to(regex_iterator_impl<BidiIter> const &that) const + { + return this->rex_.regex_id() == that.rex_.regex_id() + && this->state_.begin_ == that.state_.begin_ + && this->state_.cur_ == that.state_.cur_ + && this->state_.end_ == that.state_.end_ + && this->flags_ == that.flags_ + ; + } + + basic_regex<BidiIter> rex_; + match_results<BidiIter> what_; + match_state<BidiIter> state_; + regex_constants::match_flag_type const flags_; + bool not_null_; +}; + +} // namespace detail + +////////////////////////////////////////////////////////////////////////// +// regex_iterator +// +template<typename BidiIter> +struct regex_iterator +{ + typedef basic_regex<BidiIter> regex_type; + typedef match_results<BidiIter> value_type; + typedef typename iterator_difference<BidiIter>::type difference_type; + typedef value_type const *pointer; + typedef value_type const &reference; + typedef std::forward_iterator_tag iterator_category; + + /// INTERNAL ONLY + typedef detail::regex_iterator_impl<BidiIter> impl_type_; + + regex_iterator() + : impl_() + { + } + + regex_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + : impl_() + { + if(0 != rex.regex_id()) // Empty regexes are guaranteed to match nothing + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags); + this->next_(); + } + } + + template<typename LetExpr> + regex_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + , detail::let_<LetExpr> const &args + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + : impl_() + { + if(0 != rex.regex_id()) // Empty regexes are guaranteed to match nothing + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags); + detail::bind_args(args, this->impl_->what_); + this->next_(); + } + } + + regex_iterator(regex_iterator<BidiIter> const &that) + : impl_(that.impl_) // COW + { + } + + regex_iterator<BidiIter> &operator =(regex_iterator<BidiIter> const &that) + { + this->impl_ = that.impl_; // COW + return *this; + } + + friend bool operator ==(regex_iterator<BidiIter> const &left, regex_iterator<BidiIter> const &right) + { + if(!left.impl_ || !right.impl_) + { + return !left.impl_ && !right.impl_; + } + + return left.impl_->equal_to(*right.impl_); + } + + friend bool operator !=(regex_iterator<BidiIter> const &left, regex_iterator<BidiIter> const &right) + { + return !(left == right); + } + + value_type const &operator *() const + { + return this->impl_->what_; + } + + value_type const *operator ->() const + { + return &this->impl_->what_; + } + + /// If what.prefix().first != what[0].second and if the element match_prev_avail is not set in + /// flags then sets it. Then behaves as if by calling regex_search(what[0].second, end, what, *pre, flags), + /// with the following variation: in the event that the previous match found was of zero length + /// (what[0].length() == 0) then attempts to find a non-zero length match starting at what[0].second, + /// only if that fails and provided what[0].second != suffix().second does it look for a (possibly + /// zero length) match starting from what[0].second + 1. If no further match is found then sets + /// *this equal to the end of sequence iterator. + /// \post (*this)-\>size() == pre-\>mark_count() + 1 + /// \post (*this)-\>empty() == false + /// \post (*this)-\>prefix().first == An iterator denoting the end point of the previous match found + /// \post (*this)-\>prefix().last == (**this)[0].first + /// \post (*this)-\>prefix().matched == (*this)-\>prefix().first != (*this)-\>prefix().second + /// \post (*this)-\>suffix().first == (**this)[0].second + /// \post (*this)-\>suffix().last == end + /// \post (*this)-\>suffix().matched == (*this)-\>suffix().first != (*this)-\>suffix().second + /// \post (**this)[0].first == The starting iterator for this match. + /// \post (**this)[0].second == The ending iterator for this match. + /// \post (**this)[0].matched == true if a full match was found, and false if it was a partial match (found as a result of the match_partial flag being set). + /// \post (**this)[n].first == For all integers n \< (*this)-\>size(), the start of the sequence that matched sub-expression n. Alternatively, if sub-expression n did not participate in the match, then end. + /// \post (**this)[n].second == For all integers n \< (*this)-\>size(), the end of the sequence that matched sub-expression n. Alternatively, if sub-expression n did not participate in the match, then end. + /// \post (**this)[n].matched == For all integers n \< (*this)-\>size(), true if sub-expression n participated in the match, false otherwise. + /// \post (*this)-\>position() == The distance from the start of the original sequence being iterated, to the start of this match. + regex_iterator<BidiIter> &operator ++() + { + this->fork_(); // un-share the implementation + this->next_(); + return *this; + } + + regex_iterator<BidiIter> operator ++(int) + { + regex_iterator<BidiIter> tmp(*this); + ++*this; + return tmp; + } + +private: + + /// INTERNAL ONLY + void fork_() + { + if(1 != this->impl_->use_count()) + { + // This is OK, the use_count is > 1 + impl_type_ *that = this->impl_.get(); + this->impl_ = new impl_type_ + ( + that->state_.begin_ + , that->state_.cur_ + , that->state_.end_ + , that->state_.next_search_ + , that->rex_ + , that->flags_ + , that->not_null_ + ); + detail::core_access<BidiIter>::get_action_args(this->impl_->what_) + = detail::core_access<BidiIter>::get_action_args(that->what_); + } + } + + /// INTERNAL ONLY + void next_() + { + BOOST_ASSERT(this->impl_ && 1 == this->impl_->use_count()); + if(!this->impl_->next()) + { + this->impl_ = 0; + } + } + + intrusive_ptr<impl_type_> impl_; +}; + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_primitives.hpp b/boost/xpressive/regex_primitives.hpp new file mode 100644 index 0000000000..11230f60df --- /dev/null +++ b/boost/xpressive/regex_primitives.hpp @@ -0,0 +1,927 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_primitives.hpp +/// Contains the syntax elements for writing static regular expressions. +// +// 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_REGEX_PRIMITIVES_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_PRIMITIVES_HPP_EAN_10_04_2005 + +#include <vector> +#include <climits> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/preprocessor/cat.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/core/matchers.hpp> +#include <boost/xpressive/detail/core/regex_domain.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +// Doxygen can't handle proto :-( +#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED +# include <boost/proto/core.hpp> +# include <boost/proto/transform/arg.hpp> +# include <boost/proto/transform/when.hpp> +# include <boost/xpressive/detail/core/icase.hpp> +# include <boost/xpressive/detail/static/compile.hpp> +# include <boost/xpressive/detail/static/modifier.hpp> +#endif + +namespace boost { namespace xpressive { namespace detail +{ + + typedef assert_word_placeholder<word_boundary<mpl::true_> > assert_word_boundary; + typedef assert_word_placeholder<word_begin> assert_word_begin; + typedef assert_word_placeholder<word_end> assert_word_end; + + // workaround msvc-7.1 bug with function pointer types + // within function types: + #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + #define mark_number(x) proto::call<mark_number(x)> + #define minus_one() proto::make<minus_one()> + #endif + + struct push_back : proto::callable + { + typedef int result_type; + + template<typename Subs> + int operator ()(Subs &subs, int i) const + { + subs.push_back(i); + return i; + } + }; + + struct mark_number : proto::callable + { + typedef int result_type; + + template<typename Expr> + int operator ()(Expr const &expr) const + { + return expr.mark_number_; + } + }; + + typedef mpl::int_<-1> minus_one; + + // s1 or -s1 + struct SubMatch + : proto::or_< + proto::when<basic_mark_tag, push_back(proto::_data, mark_number(proto::_value)) > + , proto::when<proto::negate<basic_mark_tag>, push_back(proto::_data, minus_one()) > + > + {}; + + struct SubMatchList + : proto::or_<SubMatch, proto::comma<SubMatchList, SubMatch> > + {}; + + template<typename Subs> + typename enable_if< + mpl::and_<proto::is_expr<Subs>, proto::matches<Subs, SubMatchList> > + , std::vector<int> + >::type + to_vector(Subs const &subs) + { + std::vector<int> subs_; + SubMatchList()(subs, 0, subs_); + return subs_; + } + + #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + #undef mark_number + #undef minus_one + #endif + + // replace "Expr" with "keep(*State) >> Expr" + struct skip_primitives : proto::transform<skip_primitives> + { + template<typename Expr, typename State, typename Data> + struct impl : proto::transform_impl<Expr, State, Data> + { + typedef + typename proto::shift_right< + typename proto::unary_expr< + keeper_tag + , typename proto::dereference<State>::type + >::type + , Expr + >::type + result_type; + + result_type operator ()( + typename impl::expr_param expr + , typename impl::state_param state + , typename impl::data_param + ) const + { + result_type that = {{{state}}, expr}; + return that; + } + }; + }; + + struct Primitives + : proto::or_< + proto::terminal<proto::_> + , proto::comma<proto::_, proto::_> + , proto::subscript<proto::terminal<set_initializer>, proto::_> + , proto::assign<proto::terminal<set_initializer>, proto::_> + , proto::assign<proto::terminal<attribute_placeholder<proto::_> >, proto::_> + , proto::complement<Primitives> + > + {}; + + struct SkipGrammar + : proto::or_< + proto::when<Primitives, skip_primitives> + , proto::assign<proto::terminal<mark_placeholder>, SkipGrammar> // don't "skip" mark tags + , proto::subscript<SkipGrammar, proto::_> // don't put skips in actions + , proto::binary_expr<modifier_tag, proto::_, SkipGrammar> // don't skip modifiers + , proto::unary_expr<lookbehind_tag, proto::_> // don't skip lookbehinds + , proto::nary_expr<proto::_, proto::vararg<SkipGrammar> > // everything else is fair game! + > + {}; + + template<typename Skip> + struct skip_directive + { + typedef typename proto::result_of::as_expr<Skip>::type skip_type; + + skip_directive(Skip const &skip) + : skip_(proto::as_expr(skip)) + {} + + template<typename Sig> + struct result; + + template<typename This, typename Expr> + struct result<This(Expr)> + { + typedef + SkipGrammar::impl< + typename proto::result_of::as_expr<Expr>::type + , skip_type const & + , mpl::void_ & + > + skip_transform; + + typedef + typename proto::shift_right< + typename skip_transform::result_type + , typename proto::dereference<skip_type>::type + >::type + type; + }; + + template<typename Expr> + typename result<skip_directive(Expr)>::type + operator ()(Expr const &expr) const + { + mpl::void_ ignore; + typedef result<skip_directive(Expr)> result_fun; + typename result_fun::type that = { + typename result_fun::skip_transform()(proto::as_expr(expr), this->skip_, ignore) + , {skip_} + }; + return that; + } + + private: + skip_type skip_; + }; + +/* +/////////////////////////////////////////////////////////////////////////////// +/// INTERNAL ONLY +// BOOST_XPRESSIVE_GLOBAL +// for defining globals that neither violate the One Definition Rule nor +// lead to undefined behavior due to global object initialization order. +//#define BOOST_XPRESSIVE_GLOBAL(type, name, init) \ +// namespace detail \ +// { \ +// template<int Dummy> \ +// struct BOOST_PP_CAT(global_pod_, name) \ +// { \ +// static type const value; \ +// private: \ +// union type_must_be_pod \ +// { \ +// type t; \ +// char ch; \ +// } u; \ +// }; \ +// template<int Dummy> \ +// type const BOOST_PP_CAT(global_pod_, name)<Dummy>::value = init; \ +// } \ +// type const &name = detail::BOOST_PP_CAT(global_pod_, name)<0>::value +*/ + + +} // namespace detail + +/// INTERNAL ONLY (for backwards compatibility) +unsigned int const repeat_max = UINT_MAX-1; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief For infinite repetition of a sub-expression. +/// +/// Magic value used with the repeat\<\>() function template +/// to specify an unbounded repeat. Use as: repeat<17, inf>('a'). +/// The equivalent in perl is /a{17,}/. +unsigned int const inf = UINT_MAX-1; + +/// INTERNAL ONLY (for backwards compatibility) +proto::terminal<detail::epsilon_matcher>::type const epsilon = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Successfully matches nothing. +/// +/// Successfully matches a zero-width sequence. nil always succeeds and +/// never consumes any characters. +proto::terminal<detail::epsilon_matcher>::type const nil = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches an alpha-numeric character. +/// +/// The regex traits are used to determine which characters are alpha-numeric. +/// To match any character that is not alpha-numeric, use ~alnum. +/// +/// \attention alnum is equivalent to /[[:alnum:]]/ in perl. ~alnum is equivalent +/// to /[[:^alnum:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const alnum = {{"alnum", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches an alphabetic character. +/// +/// The regex traits are used to determine which characters are alphabetic. +/// To match any character that is not alphabetic, use ~alpha. +/// +/// \attention alpha is equivalent to /[[:alpha:]]/ in perl. ~alpha is equivalent +/// to /[[:^alpha:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const alpha = {{"alpha", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a blank (horizonal white-space) character. +/// +/// The regex traits are used to determine which characters are blank characters. +/// To match any character that is not blank, use ~blank. +/// +/// \attention blank is equivalent to /[[:blank:]]/ in perl. ~blank is equivalent +/// to /[[:^blank:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const blank = {{"blank", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a control character. +/// +/// The regex traits are used to determine which characters are control characters. +/// To match any character that is not a control character, use ~cntrl. +/// +/// \attention cntrl is equivalent to /[[:cntrl:]]/ in perl. ~cntrl is equivalent +/// to /[[:^cntrl:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const cntrl = {{"cntrl", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a digit character. +/// +/// The regex traits are used to determine which characters are digits. +/// To match any character that is not a digit, use ~digit. +/// +/// \attention digit is equivalent to /[[:digit:]]/ in perl. ~digit is equivalent +/// to /[[:^digit:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const digit = {{"digit", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a graph character. +/// +/// The regex traits are used to determine which characters are graphable. +/// To match any character that is not graphable, use ~graph. +/// +/// \attention graph is equivalent to /[[:graph:]]/ in perl. ~graph is equivalent +/// to /[[:^graph:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const graph = {{"graph", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a lower-case character. +/// +/// The regex traits are used to determine which characters are lower-case. +/// To match any character that is not a lower-case character, use ~lower. +/// +/// \attention lower is equivalent to /[[:lower:]]/ in perl. ~lower is equivalent +/// to /[[:^lower:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const lower = {{"lower", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a printable character. +/// +/// The regex traits are used to determine which characters are printable. +/// To match any character that is not printable, use ~print. +/// +/// \attention print is equivalent to /[[:print:]]/ in perl. ~print is equivalent +/// to /[[:^print:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const print = {{"print", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a punctuation character. +/// +/// The regex traits are used to determine which characters are punctuation. +/// To match any character that is not punctuation, use ~punct. +/// +/// \attention punct is equivalent to /[[:punct:]]/ in perl. ~punct is equivalent +/// to /[[:^punct:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const punct = {{"punct", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a space character. +/// +/// The regex traits are used to determine which characters are space characters. +/// To match any character that is not white-space, use ~space. +/// +/// \attention space is equivalent to /[[:space:]]/ in perl. ~space is equivalent +/// to /[[:^space:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const space = {{"space", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches an upper-case character. +/// +/// The regex traits are used to determine which characters are upper-case. +/// To match any character that is not upper-case, use ~upper. +/// +/// \attention upper is equivalent to /[[:upper:]]/ in perl. ~upper is equivalent +/// to /[[:^upper:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const upper = {{"upper", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a hexadecimal digit character. +/// +/// The regex traits are used to determine which characters are hex digits. +/// To match any character that is not a hex digit, use ~xdigit. +/// +/// \attention xdigit is equivalent to /[[:xdigit:]]/ in perl. ~xdigit is equivalent +/// to /[[:^xdigit:]]/ in perl. +proto::terminal<detail::posix_charset_placeholder>::type const xdigit = {{"xdigit", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Beginning of sequence assertion. +/// +/// For the character sequence [begin, end), 'bos' matches the +/// zero-width sub-sequence [begin, begin). +proto::terminal<detail::assert_bos_matcher>::type const bos = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief End of sequence assertion. +/// +/// For the character sequence [begin, end), +/// 'eos' matches the zero-width sub-sequence [end, end). +/// +/// \attention Unlike the perl end of sequence assertion \$, 'eos' will +/// not match at the position [end-1, end-1) if *(end-1) is '\\n'. To +/// get that behavior, use (!_n >> eos). +proto::terminal<detail::assert_eos_matcher>::type const eos = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Beginning of line assertion. +/// +/// 'bol' matches the zero-width sub-sequence +/// immediately following a logical newline sequence. The regex traits +/// is used to determine what constitutes a logical newline sequence. +proto::terminal<detail::assert_bol_placeholder>::type const bol = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief End of line assertion. +/// +/// 'eol' matches the zero-width sub-sequence +/// immediately preceeding a logical newline sequence. The regex traits +/// is used to determine what constitutes a logical newline sequence. +proto::terminal<detail::assert_eol_placeholder>::type const eol = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Beginning of word assertion. +/// +/// 'bow' matches the zero-width sub-sequence +/// immediately following a non-word character and preceeding a word character. +/// The regex traits are used to determine what constitutes a word character. +proto::terminal<detail::assert_word_begin>::type const bow = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief End of word assertion. +/// +/// 'eow' matches the zero-width sub-sequence +/// immediately following a word character and preceeding a non-word character. +/// The regex traits are used to determine what constitutes a word character. +proto::terminal<detail::assert_word_end>::type const eow = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Word boundary assertion. +/// +/// '_b' matches the zero-width sub-sequence at the beginning or the end of a word. +/// It is equivalent to (bow | eow). The regex traits are used to determine what +/// constitutes a word character. To match a non-word boundary, use ~_b. +/// +/// \attention _b is like \\b in perl. ~_b is like \\B in perl. +proto::terminal<detail::assert_word_boundary>::type const _b = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a word character. +/// +/// '_w' matches a single word character. The regex traits are used to determine which +/// characters are word characters. Use ~_w to match a character that is not a word +/// character. +/// +/// \attention _w is like \\w in perl. ~_w is like \\W in perl. +proto::terminal<detail::posix_charset_placeholder>::type const _w = {{"w", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a digit character. +/// +/// '_d' matches a single digit character. The regex traits are used to determine which +/// characters are digits. Use ~_d to match a character that is not a digit +/// character. +/// +/// \attention _d is like \\d in perl. ~_d is like \\D in perl. +proto::terminal<detail::posix_charset_placeholder>::type const _d = {{"d", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a space character. +/// +/// '_s' matches a single space character. The regex traits are used to determine which +/// characters are space characters. Use ~_s to match a character that is not a space +/// character. +/// +/// \attention _s is like \\s in perl. ~_s is like \\S in perl. +proto::terminal<detail::posix_charset_placeholder>::type const _s = {{"s", false}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a literal newline character, '\\n'. +/// +/// '_n' matches a single newline character, '\\n'. Use ~_n to match a character +/// that is not a newline. +/// +/// \attention ~_n is like '.' in perl without the /s modifier. +proto::terminal<char>::type const _n = {'\n'}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches a logical newline sequence. +/// +/// '_ln' matches a logical newline sequence. This can be any character in the +/// line separator class, as determined by the regex traits, or the '\\r\\n' sequence. +/// For the purpose of back-tracking, '\\r\\n' is treated as a unit. +/// To match any one character that is not a logical newline, use ~_ln. +detail::logical_newline_xpression const _ln = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Matches any one character. +/// +/// Match any character, similar to '.' in perl syntax with the /s modifier. +/// '_' matches any one character, including the newline. +/// +/// \attention To match any character except the newline, use ~_n +proto::terminal<detail::any_matcher>::type const _ = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Reference to the current regex object +/// +/// Useful when constructing recursive regular expression objects. The 'self' +/// identifier is a short-hand for the current regex object. For instance, +/// sregex rx = '(' >> (self | nil) >> ')'; will create a regex object that +/// matches balanced parens such as "((()))". +proto::terminal<detail::self_placeholder>::type const self = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Used to create character sets. +/// +/// There are two ways to create character sets with the 'set' identifier. The +/// easiest is to create a comma-separated list of the characters in the set, +/// as in (set= 'a','b','c'). This set will match 'a', 'b', or 'c'. The other +/// way is to define the set as an argument to the set subscript operator. +/// For instance, set[ 'a' | range('b','c') | digit ] will match an 'a', 'b', +/// 'c' or a digit character. +/// +/// To complement a set, apply the '~' operator. For instance, ~(set= 'a','b','c') +/// will match any character that is not an 'a', 'b', or 'c'. +/// +/// Sets can be composed of other, possibly complemented, sets. For instance, +/// set[ ~digit | ~(set= 'a','b','c') ]. +detail::set_initializer_type const set = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Sub-match placeholder type, used to create named captures in +/// static regexes. +/// +/// \c mark_tag is the type of the global sub-match placeholders \c s0, \c s1, etc.. You +/// can use the \c mark_tag type to create your own sub-match placeholders with +/// more meaningful names. This is roughly equivalent to the "named capture" +/// feature of dynamic regular expressions. +/// +/// To create a named sub-match placeholder, initialize it with a unique integer. +/// The integer must only be unique within the regex in which the placeholder +/// is used. Then you can use it within static regexes to created sub-matches +/// by assigning a sub-expression to it, or to refer back to already created +/// sub-matches. +/// +/// \code +/// mark_tag number(1); // "number" is now equivalent to "s1" +/// // Match a number, followed by a space and the same number again +/// sregex rx = (number = +_d) >> ' ' >> number; +/// \endcode +/// +/// After a successful \c regex_match() or \c regex_search(), the sub-match placeholder +/// can be used to index into the <tt>match_results\<\></tt> object to retrieve the +/// corresponding sub-match. +struct mark_tag + : proto::extends<detail::basic_mark_tag, mark_tag, detail::regex_domain> +{ +private: + typedef proto::extends<detail::basic_mark_tag, mark_tag, detail::regex_domain> base_type; + + static detail::basic_mark_tag make_tag(int mark_nbr) + { + detail::basic_mark_tag mark = {{mark_nbr}}; + return mark; + } + +public: + /// \brief Initialize a mark_tag placeholder + /// \param mark_nbr An integer that uniquely identifies this \c mark_tag + /// within the static regexes in which this \c mark_tag will be used. + /// \pre <tt>mark_nbr \> 0</tt> + mark_tag(int mark_nbr) + : base_type(mark_tag::make_tag(mark_nbr)) + { + // Marks numbers must be integers greater than 0. + BOOST_ASSERT(mark_nbr > 0); + } + + /// INTERNAL ONLY + operator detail::basic_mark_tag const &() const + { + return this->proto_base(); + } + + BOOST_PROTO_EXTENDS_USING_ASSIGN_NON_DEPENDENT(mark_tag) +}; + +// This macro is used when declaring mark_tags that are global because +// it guarantees that they are statically initialized. That avoids +// order-of-initialization bugs. In user code, the simpler: mark_tag s0(0); +// would be preferable. +/// INTERNAL ONLY +#define BOOST_XPRESSIVE_GLOBAL_MARK_TAG(NAME, VALUE) \ + boost::xpressive::mark_tag::proto_base_expr const NAME = {{VALUE}} \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Sub-match placeholder, like $& in Perl +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s0, 0); + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Sub-match placeholder, like $1 in perl. +/// +/// To create a sub-match, assign a sub-expression to the sub-match placeholder. +/// For instance, (s1= _) will match any one character and remember which +/// character was matched in the 1st sub-match. Later in the pattern, you can +/// refer back to the sub-match. For instance, (s1= _) >> s1 will match any +/// character, and then match the same character again. +/// +/// After a successful regex_match() or regex_search(), the sub-match placeholders +/// can be used to index into the match_results\<\> object to retrieve the Nth +/// sub-match. +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s1, 1); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s2, 2); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s3, 3); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s4, 4); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s5, 5); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s6, 6); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s7, 7); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s8, 8); +BOOST_XPRESSIVE_GLOBAL_MARK_TAG(s9, 9); + +// NOTE: For the purpose of xpressive's documentation, make icase() look like an +// ordinary function. In reality, it is a function object defined in detail/icase.hpp +// so that it can serve double-duty as regex_constants::icase, the syntax_option_type. +#ifdef BOOST_XPRESSIVE_DOXYGEN_INVOKED +/////////////////////////////////////////////////////////////////////////////// +/// \brief Makes a sub-expression case-insensitive. +/// +/// Use icase() to make a sub-expression case-insensitive. For instance, +/// "foo" >> icase(set['b'] >> "ar") will match "foo" exactly followed by +/// "bar" irrespective of case. +template<typename Expr> detail::unspecified icase(Expr const &expr) { return 0; } +#endif + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Makes a literal into a regular expression. +/// +/// Use as_xpr() to turn a literal into a regular expression. For instance, +/// "foo" >> "bar" will not compile because both operands to the right-shift +/// operator are const char*, and no such operator exists. Use as_xpr("foo") >> "bar" +/// instead. +/// +/// You can use as_xpr() with character literals in addition to string literals. +/// For instance, as_xpr('a') will match an 'a'. You can also complement a +/// character literal, as with ~as_xpr('a'). This will match any one character +/// that is not an 'a'. +#ifdef BOOST_XPRESSIVE_DOXYGEN_INVOKED +template<typename Literal> detail::unspecified as_xpr(Literal const &literal) { return 0; } +#else +proto::functional::as_expr<> const as_xpr = {}; +#endif + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Embed a regex object by reference. +/// +/// \param rex The basic_regex object to embed by reference. +template<typename BidiIter> +inline typename proto::terminal<reference_wrapper<basic_regex<BidiIter> const> >::type const +by_ref(basic_regex<BidiIter> const &rex) +{ + reference_wrapper<basic_regex<BidiIter> const> ref(rex); + return proto::terminal<reference_wrapper<basic_regex<BidiIter> const> >::type::make(ref); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Match a range of characters. +/// +/// Match any character in the range [ch_min, ch_max]. +/// +/// \param ch_min The lower end of the range to match. +/// \param ch_max The upper end of the range to match. +template<typename Char> +inline typename proto::terminal<detail::range_placeholder<Char> >::type const +range(Char ch_min, Char ch_max) +{ + detail::range_placeholder<Char> that = {ch_min, ch_max, false}; + return proto::terminal<detail::range_placeholder<Char> >::type::make(that); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Make a sub-expression optional. Equivalent to !as_xpr(expr). +/// +/// \param expr The sub-expression to make optional. +template<typename Expr> +typename proto::result_of::make_expr< + proto::tag::logical_not + , proto::default_domain + , Expr const & +>::type const +optional(Expr const &expr) +{ + return proto::make_expr< + proto::tag::logical_not + , proto::default_domain + >(boost::ref(expr)); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Repeat a sub-expression multiple times. +/// +/// There are two forms of the repeat\<\>() function template. To match a +/// sub-expression N times, use repeat\<N\>(expr). To match a sub-expression +/// from M to N times, use repeat\<M,N\>(expr). +/// +/// The repeat\<\>() function creates a greedy quantifier. To make the quantifier +/// non-greedy, apply the unary minus operator, as in -repeat\<M,N\>(expr). +/// +/// \param expr The sub-expression to repeat. +template<unsigned int Min, unsigned int Max, typename Expr> +typename proto::result_of::make_expr< + detail::generic_quant_tag<Min, Max> + , proto::default_domain + , Expr const & +>::type const +repeat(Expr const &expr) +{ + return proto::make_expr< + detail::generic_quant_tag<Min, Max> + , proto::default_domain + >(boost::ref(expr)); +} + +/// \overload +/// +template<unsigned int Count, typename Expr2> +typename proto::result_of::make_expr< + detail::generic_quant_tag<Count, Count> + , proto::default_domain + , Expr2 const & +>::type const +repeat(Expr2 const &expr2) +{ + return proto::make_expr< + detail::generic_quant_tag<Count, Count> + , proto::default_domain + >(boost::ref(expr2)); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Create an independent sub-expression. +/// +/// Turn off back-tracking for a sub-expression. Any branches or repeats within +/// the sub-expression will match only one way, and no other alternatives are +/// tried. +/// +/// \attention keep(expr) is equivalent to the perl (?>...) extension. +/// +/// \param expr The sub-expression to modify. +template<typename Expr> +typename proto::result_of::make_expr< + detail::keeper_tag + , proto::default_domain + , Expr const & +>::type const +keep(Expr const &expr) +{ + return proto::make_expr< + detail::keeper_tag + , proto::default_domain + >(boost::ref(expr)); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Look-ahead assertion. +/// +/// before(expr) succeeds if the expr sub-expression would match at the current +/// position in the sequence, but expr is not included in the match. For instance, +/// before("foo") succeeds if we are before a "foo". Look-ahead assertions can be +/// negated with the bit-compliment operator. +/// +/// \attention before(expr) is equivalent to the perl (?=...) extension. +/// ~before(expr) is a negative look-ahead assertion, equivalent to the +/// perl (?!...) extension. +/// +/// \param expr The sub-expression to put in the look-ahead assertion. +template<typename Expr> +typename proto::result_of::make_expr< + detail::lookahead_tag + , proto::default_domain + , Expr const & +>::type const +before(Expr const &expr) +{ + return proto::make_expr< + detail::lookahead_tag + , proto::default_domain + >(boost::ref(expr)); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Look-behind assertion. +/// +/// after(expr) succeeds if the expr sub-expression would match at the current +/// position minus N in the sequence, where N is the width of expr. expr is not included in +/// the match. For instance, after("foo") succeeds if we are after a "foo". Look-behind +/// assertions can be negated with the bit-complement operator. +/// +/// \attention after(expr) is equivalent to the perl (?<=...) extension. +/// ~after(expr) is a negative look-behind assertion, equivalent to the +/// perl (?<!...) extension. +/// +/// \param expr The sub-expression to put in the look-ahead assertion. +/// +/// \pre expr cannot match a variable number of characters. +template<typename Expr> +typename proto::result_of::make_expr< + detail::lookbehind_tag + , proto::default_domain + , Expr const & +>::type const +after(Expr const &expr) +{ + return proto::make_expr< + detail::lookbehind_tag + , proto::default_domain + >(boost::ref(expr)); +} + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Specify a regex traits or a std::locale. +/// +/// imbue() instructs the regex engine to use the specified traits or locale +/// when matching the regex. The entire expression must use the same traits/locale. +/// For instance, the following specifies a locale for use with a regex: +/// std::locale loc; +/// sregex rx = imbue(loc)(+digit); +/// +/// \param loc The std::locale or regex traits object. +template<typename Locale> +inline detail::modifier_op<detail::locale_modifier<Locale> > const +imbue(Locale const &loc) +{ + detail::modifier_op<detail::locale_modifier<Locale> > mod = + { + detail::locale_modifier<Locale>(loc) + , regex_constants::ECMAScript + }; + return mod; +} + +proto::terminal<detail::attribute_placeholder<mpl::int_<1> > >::type const a1 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<2> > >::type const a2 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<3> > >::type const a3 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<4> > >::type const a4 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<5> > >::type const a5 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<6> > >::type const a6 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<7> > >::type const a7 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<8> > >::type const a8 = {{}}; +proto::terminal<detail::attribute_placeholder<mpl::int_<9> > >::type const a9 = {{}}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief Specify which characters to skip when matching a regex. +/// +/// <tt>skip()</tt> instructs the regex engine to skip certain characters when matching +/// a regex. It is most useful for writing regexes that ignore whitespace. +/// For instance, the following specifies a regex that skips whitespace and +/// punctuation: +/// +/// \code +/// // A sentence is one or more words separated by whitespace +/// // and punctuation. +/// sregex word = +alpha; +/// sregex sentence = skip(set[_s | punct])( +word ); +/// \endcode +/// +/// The way it works in the above example is to insert +/// <tt>keep(*set[_s | punct])</tt> before each primitive within the regex. +/// A "primitive" includes terminals like strings, character sets and nested +/// regexes. A final <tt>*set[_s | punct]</tt> is added to the end of the +/// regex. The regex <tt>sentence</tt> specified above is equivalent to +/// the following: +/// +/// \code +/// sregex sentence = +( keep(*set[_s | punct]) >> word ) +/// >> *set[_s | punct]; +/// \endcode +/// +/// \attention Skipping does not affect how nested regexes are handled because +/// they are treated atomically. String literals are also treated +/// atomically; that is, no skipping is done within a string literal. So +/// <tt>skip(_s)("this that")</tt> is not the same as +/// <tt>skip(_s)("this" >> as_xpr("that"))</tt>. The first will only match +/// when there is only one space between "this" and "that". The second will +/// skip any and all whitespace between "this" and "that". +/// +/// \param skip A regex that specifies which characters to skip. +template<typename Skip> +detail::skip_directive<Skip> skip(Skip const &skip) +{ + return detail::skip_directive<Skip>(skip); +} + +namespace detail +{ + inline void ignore_unused_regex_primitives() + { + detail::ignore_unused(repeat_max); + detail::ignore_unused(inf); + detail::ignore_unused(epsilon); + detail::ignore_unused(nil); + detail::ignore_unused(alnum); + detail::ignore_unused(bos); + detail::ignore_unused(eos); + detail::ignore_unused(bol); + detail::ignore_unused(eol); + detail::ignore_unused(bow); + detail::ignore_unused(eow); + detail::ignore_unused(_b); + detail::ignore_unused(_w); + detail::ignore_unused(_d); + detail::ignore_unused(_s); + detail::ignore_unused(_n); + detail::ignore_unused(_ln); + detail::ignore_unused(_); + detail::ignore_unused(self); + detail::ignore_unused(set); + detail::ignore_unused(s0); + detail::ignore_unused(s1); + detail::ignore_unused(s2); + detail::ignore_unused(s3); + detail::ignore_unused(s4); + detail::ignore_unused(s5); + detail::ignore_unused(s6); + detail::ignore_unused(s7); + detail::ignore_unused(s8); + detail::ignore_unused(s9); + detail::ignore_unused(a1); + detail::ignore_unused(a2); + detail::ignore_unused(a3); + detail::ignore_unused(a4); + detail::ignore_unused(a5); + detail::ignore_unused(a6); + detail::ignore_unused(a7); + detail::ignore_unused(a8); + detail::ignore_unused(a9); + detail::ignore_unused(as_xpr); + } +} + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_token_iterator.hpp b/boost/xpressive/regex_token_iterator.hpp new file mode 100644 index 0000000000..0eb18d57aa --- /dev/null +++ b/boost/xpressive/regex_token_iterator.hpp @@ -0,0 +1,370 @@ + /////////////////////////////////////////////////////////////////////////////// +/// \file regex_token_iterator.hpp +/// Contains the definition of regex_token_iterator, and STL-compatible iterator +/// for tokenizing a string using a regular expression. +// +// 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_REGEX_TOKEN_ITERATOR_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_TOKEN_ITERATOR_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <vector> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/xpressive/regex_iterator.hpp> + +namespace boost { namespace xpressive { namespace detail +{ + +////////////////////////////////////////////////////////////////////////// +// regex_token_iterator_impl +// +template<typename BidiIter> +struct regex_token_iterator_impl + : counted_base<regex_token_iterator_impl<BidiIter> > +{ + typedef sub_match<BidiIter> value_type; + + regex_token_iterator_impl + ( + BidiIter begin + , BidiIter cur + , BidiIter end + , BidiIter next_search + , basic_regex<BidiIter> const &rex + , regex_constants::match_flag_type flags = regex_constants::match_default + , std::vector<int> subs = std::vector<int>(1, 0) + , int n = -2 + , bool not_null = false + ) + : iter_(begin, cur, end, next_search, rex, flags, not_null) + , result_() + , n_((-2 == n) ? (int)subs.size() - 1 : n) + , subs_() + { + BOOST_ASSERT(0 != subs.size()); + this->subs_.swap(subs); + } + + bool next() + { + if(-1 != this->n_) + { + BidiIter cur = this->iter_.state_.cur_; + if(0 != (++this->n_ %= (int)this->subs_.size()) || this->iter_.next()) + { + this->result_ = (-1 == this->subs_[ this->n_ ]) + ? this->iter_.what_.prefix() + : this->iter_.what_[ this->subs_[ this->n_ ] ]; + return true; + } + else if(-1 == this->subs_[ this->n_-- ] && cur != this->iter_.state_.end_) + { + this->result_ = value_type(cur, this->iter_.state_.end_, true); + return true; + } + } + + return false; + } + + bool equal_to(regex_token_iterator_impl<BidiIter> const &that) const + { + return this->iter_.equal_to(that.iter_) && this->n_ == that.n_; + } + + regex_iterator_impl<BidiIter> iter_; + value_type result_; + int n_; + std::vector<int> subs_; +}; + +inline int get_mark_number(int i) +{ + return i; +} + +inline std::vector<int> to_vector(int subs) +{ + return std::vector<int>(1, subs); +} + +inline std::vector<int> const &to_vector(std::vector<int> const &subs) +{ + return subs; +} + +template<typename Int, std::size_t Size> +inline std::vector<int> to_vector(Int const (&sub_matches)[ Size ]) +{ + // so that people can specify sub-match indices inline with + // string literals, like "\1\2\3", leave off the trailing '\0' + std::size_t const size = Size - is_same<Int, char>::value; + std::vector<int> vect(size); + for(std::size_t i = 0; i < size; ++i) + { + vect[i] = get_mark_number(sub_matches[i]); + } + return vect; +} + +template<typename Int> +inline std::vector<int> to_vector(std::vector<Int> const &sub_matches) +{ + BOOST_MPL_ASSERT((is_convertible<Int, int>)); + return std::vector<int>(sub_matches.begin(), sub_matches.end()); +} + +} // namespace detail + +////////////////////////////////////////////////////////////////////////// +// regex_token_iterator +// +template<typename BidiIter> +struct regex_token_iterator +{ + typedef basic_regex<BidiIter> regex_type; + typedef typename iterator_value<BidiIter>::type char_type; + typedef sub_match<BidiIter> value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type const *pointer; + typedef value_type const &reference; + typedef std::forward_iterator_tag iterator_category; + + /// INTERNAL ONLY + typedef detail::regex_token_iterator_impl<BidiIter> impl_type_; + + /// \post \c *this is the end of sequence iterator. + regex_token_iterator() + : impl_() + { + } + + /// \param begin The beginning of the character range to search. + /// \param end The end of the character range to search. + /// \param rex The regex pattern to search for. + /// \pre \c [begin,end) is a valid range. + regex_token_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + ) + : impl_() + { + if(0 != rex.regex_id()) + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex); + this->next_(); + } + } + + /// \param begin The beginning of the character range to search. + /// \param end The end of the character range to search. + /// \param rex The regex pattern to search for. + /// \param args A let() expression with argument bindings for semantic actions. + /// \pre \c [begin,end) is a valid range. + template<typename LetExpr> + regex_token_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + , detail::let_<LetExpr> const &args + ) + : impl_() + { + if(0 != rex.regex_id()) + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex); + detail::bind_args(args, this->impl_->iter_.what_); + this->next_(); + } + } + + /// \param begin The beginning of the character range to search. + /// \param end The end of the character range to search. + /// \param rex The regex pattern to search for. + /// \param flags Optional match flags, used to control how the expression is matched against the sequence. (See match_flag_type.) + /// \pre \c [begin,end) is a valid range. + /// \pre \c subs is either an integer greater or equal to -1, + /// or else an array or non-empty \c std::vector\<\> of such integers. + template<typename Subs> + regex_token_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + , Subs const &subs + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + : impl_() + { + if(0 != rex.regex_id()) + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags, detail::to_vector(subs)); + this->next_(); + } + } + + /// \param begin The beginning of the character range to search. + /// \param end The end of the character range to search. + /// \param rex The regex pattern to search for. + /// \param args A let() expression with argument bindings for semantic actions. + /// \param flags Optional match flags, used to control how the expression is matched against the sequence. (See match_flag_type.) + /// \pre \c [begin,end) is a valid range. + /// \pre \c subs is either an integer greater or equal to -1, + /// or else an array or non-empty \c std::vector\<\> of such integers. + template<typename Subs, typename LetExpr> + regex_token_iterator + ( + BidiIter begin + , BidiIter end + , basic_regex<BidiIter> const &rex + , Subs const &subs + , detail::let_<LetExpr> const &args + , regex_constants::match_flag_type flags = regex_constants::match_default + ) + : impl_() + { + if(0 != rex.regex_id()) + { + this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags, detail::to_vector(subs)); + detail::bind_args(args, this->impl_->iter_.what_); + this->next_(); + } + } + + /// \post <tt>*this == that</tt> + regex_token_iterator(regex_token_iterator<BidiIter> const &that) + : impl_(that.impl_) // COW + { + } + + /// \post <tt>*this == that</tt> + regex_token_iterator<BidiIter> &operator =(regex_token_iterator<BidiIter> const &that) + { + this->impl_ = that.impl_; // COW + return *this; + } + + friend bool operator ==(regex_token_iterator<BidiIter> const &left, regex_token_iterator<BidiIter> const &right) + { + if(!left.impl_ || !right.impl_) + { + return !left.impl_ && !right.impl_; + } + + return left.impl_->equal_to(*right.impl_); + } + + friend bool operator !=(regex_token_iterator<BidiIter> const &left, regex_token_iterator<BidiIter> const &right) + { + return !(left == right); + } + + value_type const &operator *() const + { + return this->impl_->result_; + } + + value_type const *operator ->() const + { + return &this->impl_->result_; + } + + /// If N == -1 then sets *this equal to the end of sequence iterator. + /// Otherwise if N+1 \< subs.size(), then increments N and sets result equal to + /// ((subs[N] == -1) ? value_type(what.prefix().str()) : value_type(what[subs[N]].str())). + /// Otherwise if what.prefix().first != what[0].second and if the element match_prev_avail is + /// not set in flags then sets it. Then locates the next match as if by calling + /// regex_search(what[0].second, end, what, *pre, flags), with the following variation: + /// in the event that the previous match found was of zero length (what[0].length() == 0) + /// then attempts to find a non-zero length match starting at what[0].second, only if that + /// fails and provided what[0].second != suffix().second does it look for a (possibly zero + /// length) match starting from what[0].second + 1. If such a match is found then sets N + /// equal to zero, and sets result equal to + /// ((subs[N] == -1) ? value_type(what.prefix().str()) : value_type(what[subs[N]].str())). + /// Otherwise if no further matches were found, then let last_end be the endpoint of the last + /// match that was found. Then if last_end != end and subs[0] == -1 sets N equal to -1 and + /// sets result equal to value_type(last_end, end). Otherwise sets *this equal to the end + /// of sequence iterator. + regex_token_iterator<BidiIter> &operator ++() + { + this->fork_(); // un-share the implementation + this->next_(); + return *this; + } + + regex_token_iterator<BidiIter> operator ++(int) + { + regex_token_iterator<BidiIter> tmp(*this); + ++*this; + return tmp; + } + +private: + + /// INTERNAL ONLY + void fork_() + { + if(1 != this->impl_->use_count()) + { + intrusive_ptr<impl_type_> clone = new impl_type_ + ( + this->impl_->iter_.state_.begin_ + , this->impl_->iter_.state_.cur_ + , this->impl_->iter_.state_.end_ + , this->impl_->iter_.state_.next_search_ + , this->impl_->iter_.rex_ + , this->impl_->iter_.flags_ + , this->impl_->subs_ + , this->impl_->n_ + , this->impl_->iter_.not_null_ + ); + + // only copy the match_results struct if we have to. Note: if the next call + // to impl_->next() will return false or call regex_search, we don't need to + // copy the match_results struct. + if(-1 != this->impl_->n_ && this->impl_->n_ + 1 != static_cast<int>(this->impl_->subs_.size())) + { + // BUGBUG This is expensive -- it causes the sequence_stack to be cleared. + // Find a better way + clone->iter_.what_ = this->impl_->iter_.what_; + } + else + { + // At the very least, copy the action args + detail::core_access<BidiIter>::get_action_args(clone->iter_.what_) + = detail::core_access<BidiIter>::get_action_args(this->impl_->iter_.what_); + } + + this->impl_.swap(clone); + } + } + + /// INTERNAL ONLY + void next_() + { + BOOST_ASSERT(this->impl_ && 1 == this->impl_->use_count()); + if(!this->impl_->next()) + { + this->impl_ = 0; + } + } + + intrusive_ptr<impl_type_> impl_; +}; + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/regex_traits.hpp b/boost/xpressive/regex_traits.hpp new file mode 100644 index 0000000000..f7a03e2cb4 --- /dev/null +++ b/boost/xpressive/regex_traits.hpp @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file regex_traits.hpp +/// Includes the C regex traits or the CPP regex traits header file depending on the +/// BOOST_XPRESSIVE_USE_C_TRAITS macro. +// +// 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_REGEX_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_REGEX_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/type_traits/is_convertible.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +#ifdef BOOST_XPRESSIVE_USE_C_TRAITS +# include <boost/xpressive/traits/c_regex_traits.hpp> +#else +# include <boost/xpressive/traits/cpp_regex_traits.hpp> +#endif + +namespace boost { namespace xpressive +{ + +/////////////////////////////////////////////////////////////////////////////// +// regex_traits_version_1_tag +/// Tag used to denote that a traits class conforms to the version 1 traits +/// interface. +struct regex_traits_version_1_tag +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// regex_traits_version_2_tag +/// Tag used to denote that a traits class conforms to the version 2 traits +/// interface. +struct regex_traits_version_2_tag + : regex_traits_version_1_tag +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// regex_traits_version_1_case_fold_tag DEPRECATED use has_fold_case trait +/// INTERNAL ONLY +/// +struct regex_traits_version_1_case_fold_tag + : regex_traits_version_1_tag +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// has_fold_case +/// Trait used to denote that a traits class has the fold_case member function. +template<typename Traits> +struct has_fold_case + : is_convertible< + typename Traits::version_tag * + , regex_traits_version_1_case_fold_tag * + > +{ +}; + +/////////////////////////////////////////////////////////////////////////////// +// regex_traits +/// Thin wrapper around the default regex_traits implementation, either +/// cpp_regex_traits or c_regex_traits +/// +template<typename Char, typename Impl> +struct regex_traits + : Impl +{ + typedef typename Impl::locale_type locale_type; + + regex_traits() + : Impl() + { + } + + explicit regex_traits(locale_type const &loc) + : Impl(loc) + { + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// lookup_classname +/// INTERNAL ONLY +template<typename Traits, std::size_t N> +inline typename Traits::char_class_type +lookup_classname(Traits const &traits, char const (&cname)[N], bool icase) +{ + typename Traits::char_type name[N] = {0}; + for(std::size_t j = 0; j < N-1; ++j) + { + name[j] = traits.widen(cname[j]); + } + return traits.lookup_classname(name, name + N - 1, icase); +} + +}} + +#endif diff --git a/boost/xpressive/sub_match.hpp b/boost/xpressive/sub_match.hpp new file mode 100644 index 0000000000..5bd778ba9f --- /dev/null +++ b/boost/xpressive/sub_match.hpp @@ -0,0 +1,392 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file sub_match.hpp +/// Contains the definition of the class template sub_match\<\> +/// and associated helper functions +// +// 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_SUB_MATCH_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_SUB_MATCH_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <iosfwd> +#include <string> +#include <utility> +#include <iterator> +#include <algorithm> +#include <boost/iterator/iterator_traits.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +//{{AFX_DOC_COMMENT +/////////////////////////////////////////////////////////////////////////////// +// This is a hack to get Doxygen to show the inheritance relation between +// sub_match<T> and std::pair<T,T>. +#ifdef BOOST_XPRESSIVE_DOXYGEN_INVOKED +/// INTERNAL ONLY +namespace std +{ + /// INTERNAL ONLY + template<typename, typename> struct pair {}; +} +#endif +//}}AFX_DOC_COMMENT + +namespace boost { namespace xpressive +{ + +/////////////////////////////////////////////////////////////////////////////// +// sub_match +// +/// \brief Class template sub_match denotes the sequence of characters matched by a particular marked sub-expression. +/// +/// When the marked sub-expression denoted by an object of type sub_match\<\> participated in a +/// regular expression match then member matched evaluates to true, and members first and second +/// denote the range of characters [first,second) which formed that match. Otherwise matched is false, +/// and members first and second contained undefined values. +/// +/// If an object of type sub_match\<\> represents sub-expression 0 - that is to say the whole match - +/// then member matched is always true, unless a partial match was obtained as a result of the flag +/// match_partial being passed to a regular expression algorithm, in which case member matched is +/// false, and members first and second represent the character range that formed the partial match. +template<typename BidiIter> +struct sub_match + : std::pair<BidiIter, BidiIter> +{ +private: + /// INTERNAL ONLY + /// + struct dummy { int i_; }; + typedef int dummy::*bool_type; + +public: + typedef typename iterator_value<BidiIter>::type value_type; + typedef typename iterator_difference<BidiIter>::type difference_type; + typedef typename detail::string_type<value_type>::type string_type; + typedef BidiIter iterator; + + sub_match() + : std::pair<BidiIter, BidiIter>() + , matched(false) + { + } + + sub_match(BidiIter first, BidiIter second, bool matched_ = false) + : std::pair<BidiIter, BidiIter>(first, second) + , matched(matched_) + { + } + + string_type str() const + { + return this->matched ? string_type(this->first, this->second) : string_type(); + } + + operator string_type() const + { + return this->matched ? string_type(this->first, this->second) : string_type(); + } + + difference_type length() const + { + return this->matched ? std::distance(this->first, this->second) : 0; + } + + operator bool_type() const + { + return this->matched ? &dummy::i_ : 0; + } + + bool operator !() const + { + return !this->matched; + } + + /// \brief Performs a lexicographic string comparison + /// \param str the string against which to compare + /// \return the results of (*this).str().compare(str) + int compare(string_type const &str) const + { + return this->str().compare(str); + } + + /// \overload + /// + int compare(sub_match const &sub) const + { + return this->str().compare(sub.str()); + } + + /// \overload + /// + int compare(value_type const *ptr) const + { + return this->str().compare(ptr); + } + + /// \brief true if this sub-match participated in the full match. + bool matched; +}; + +/////////////////////////////////////////////////////////////////////////////// +/// \brief insertion operator for sending sub-matches to ostreams +/// \param sout output stream. +/// \param sub sub_match object to be written to the stream. +/// \return sout \<\< sub.str() +template<typename BidiIter, typename Char, typename Traits> +inline std::basic_ostream<Char, Traits> &operator << +( + std::basic_ostream<Char, Traits> &sout + , sub_match<BidiIter> const &sub +) +{ + typedef typename iterator_value<BidiIter>::type char_type; + if(sub.matched) + { + std::ostream_iterator<char_type, Char, Traits> iout(sout); + std::copy(sub.first, sub.second, iout); + } + return sout; +} + + +// BUGBUG make these more efficient + +template<typename BidiIter> +bool operator == (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) == 0; +} + +template<typename BidiIter> +bool operator != (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) != 0; +} + +template<typename BidiIter> +bool operator < (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) < 0; +} + +template<typename BidiIter> +bool operator <= (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) <= 0; +} + +template<typename BidiIter> +bool operator >= (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) >= 0; +} + +template<typename BidiIter> +bool operator > (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.compare(rhs) > 0; +} + +template<typename BidiIter> +bool operator == (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs == rhs.str(); +} + +template<typename BidiIter> +bool operator != (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs != rhs.str(); +} + +template<typename BidiIter> +bool operator < (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs < rhs.str(); +} + +template<typename BidiIter> +bool operator > (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs> rhs.str(); +} + +template<typename BidiIter> +bool operator >= (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs >= rhs.str(); +} + +template<typename BidiIter> +bool operator <= (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs <= rhs.str(); +} + +template<typename BidiIter> +bool operator == (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() == rhs; +} + +template<typename BidiIter> +bool operator != (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() != rhs; +} + +template<typename BidiIter> +bool operator < (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() < rhs; +} + +template<typename BidiIter> +bool operator > (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() > rhs; +} + +template<typename BidiIter> +bool operator >= (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() >= rhs; +} + +template<typename BidiIter> +bool operator <= (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() <= rhs; +} + +template<typename BidiIter> +bool operator == (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs == rhs.str(); +} + +template<typename BidiIter> +bool operator != (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs != rhs.str(); +} + +template<typename BidiIter> +bool operator < (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs < rhs.str(); +} + +template<typename BidiIter> +bool operator > (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs> rhs.str(); +} + +template<typename BidiIter> +bool operator >= (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs >= rhs.str(); +} + +template<typename BidiIter> +bool operator <= (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs <= rhs.str(); +} + +template<typename BidiIter> +bool operator == (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() == rhs; +} + +template<typename BidiIter> +bool operator != (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() != rhs; +} + +template<typename BidiIter> +bool operator < (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() < rhs; +} + +template<typename BidiIter> +bool operator > (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() > rhs; +} + +template<typename BidiIter> +bool operator >= (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() >= rhs; +} + +template<typename BidiIter> +bool operator <= (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() <= rhs; +} + +// Operator+ convenience function +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (sub_match<BidiIter> const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs.str() + rhs.str(); +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const &rhs) +{ + return lhs.str() + rhs; +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (typename iterator_value<BidiIter>::type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs + rhs.str(); +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (sub_match<BidiIter> const &lhs, typename iterator_value<BidiIter>::type const *rhs) +{ + return lhs.str() + rhs; +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (typename iterator_value<BidiIter>::type const *lhs, sub_match<BidiIter> const &rhs) +{ + return lhs + rhs.str(); +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (sub_match<BidiIter> const &lhs, typename sub_match<BidiIter>::string_type const &rhs) +{ + return lhs.str() + rhs; +} + +template<typename BidiIter> +typename sub_match<BidiIter>::string_type +operator + (typename sub_match<BidiIter>::string_type const &lhs, sub_match<BidiIter> const &rhs) +{ + return lhs + rhs.str(); +} + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/traits/c_regex_traits.hpp b/boost/xpressive/traits/c_regex_traits.hpp new file mode 100644 index 0000000000..805dcd3773 --- /dev/null +++ b/boost/xpressive/traits/c_regex_traits.hpp @@ -0,0 +1,413 @@ +////////////////////////////////////////////////////////////////////////////// +/// \file c_regex_traits.hpp +/// Contains the definition of the c_regex_traits\<\> template, which is a +/// wrapper for the C locale functions that can be used to customize the +/// behavior of static and dynamic regexes. +// +// 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_TRAITS_C_REGEX_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_TRAITS_C_REGEX_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <cstdlib> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/xpressive/traits/detail/c_ctype.hpp> + +namespace boost { namespace xpressive +{ + +namespace detail +{ + /////////////////////////////////////////////////////////////////////////////// + // empty_locale + struct empty_locale + { + }; + + /////////////////////////////////////////////////////////////////////////////// + // c_regex_traits_base + template<typename Char, std::size_t SizeOfChar = sizeof(Char)> + struct c_regex_traits_base + { + protected: + template<typename Traits> + void imbue(Traits const &tr) + { + } + }; + + template<typename Char> + struct c_regex_traits_base<Char, 1> + { + protected: + template<typename Traits> + static void imbue(Traits const &) + { + } + }; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + template<std::size_t SizeOfChar> + struct c_regex_traits_base<wchar_t, SizeOfChar> + { + protected: + template<typename Traits> + static void imbue(Traits const &) + { + } + }; + #endif + + template<typename Char> + Char c_tolower(Char); + + template<typename Char> + Char c_toupper(Char); + + template<> + inline char c_tolower(char ch) + { + using namespace std; + return static_cast<char>(tolower(static_cast<unsigned char>(ch))); + } + + template<> + inline char c_toupper(char ch) + { + using namespace std; + return static_cast<char>(toupper(static_cast<unsigned char>(ch))); + } + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + template<> + inline wchar_t c_tolower(wchar_t ch) + { + using namespace std; + return towlower(ch); + } + + template<> + inline wchar_t c_toupper(wchar_t ch) + { + using namespace std; + return towupper(ch); + } + #endif + +} // namespace detail + +/////////////////////////////////////////////////////////////////////////////// +// regex_traits_version_1_tag +// +struct regex_traits_version_1_tag; + +/////////////////////////////////////////////////////////////////////////////// +// c_regex_traits +// +/// \brief Encapsaulates the standard C locale functions for use by the +/// basic_regex\<\> class template. +template<typename Char> +struct c_regex_traits + : detail::c_regex_traits_base<Char> +{ + typedef Char char_type; + typedef std::basic_string<char_type> string_type; + typedef detail::empty_locale locale_type; + typedef typename detail::char_class_impl<Char>::char_class_type char_class_type; + typedef regex_traits_version_2_tag version_tag; + typedef detail::c_regex_traits_base<Char> base_type; + + /// Initialize a c_regex_traits object to use the global C locale. + /// + c_regex_traits(locale_type const &loc = locale_type()) + : base_type() + { + this->imbue(loc); + } + + /// Checks two c_regex_traits objects for equality + /// + /// \return true. + bool operator ==(c_regex_traits<char_type> const &) const + { + return true; + } + + /// Checks two c_regex_traits objects for inequality + /// + /// \return false. + bool operator !=(c_regex_traits<char_type> const &) const + { + return false; + } + + /// Convert a char to a Char + /// + /// \param ch The source character. + /// \return ch if Char is char, std::btowc(ch) if Char is wchar_t. + static char_type widen(char ch); + + /// Returns a hash value for a Char in the range [0, UCHAR_MAX] + /// + /// \param ch The source character. + /// \return a value between 0 and UCHAR_MAX, inclusive. + static unsigned char hash(char_type ch) + { + return static_cast<unsigned char>(std::char_traits<Char>::to_int_type(ch)); + } + + /// No-op + /// + /// \param ch The source character. + /// \return ch + static char_type translate(char_type ch) + { + return ch; + } + + /// Converts a character to lower-case using the current global C locale. + /// + /// \param ch The source character. + /// \return std::tolower(ch) if Char is char, std::towlower(ch) if Char is wchar_t. + static char_type translate_nocase(char_type ch) + { + return detail::c_tolower(ch); + } + + /// Converts a character to lower-case using the current global C locale. + /// + /// \param ch The source character. + /// \return std::tolower(ch) if Char is char, std::towlower(ch) if Char is wchar_t. + static char_type tolower(char_type ch) + { + return detail::c_tolower(ch); + } + + /// Converts a character to upper-case using the current global C locale. + /// + /// \param ch The source character. + /// \return std::toupper(ch) if Char is char, std::towupper(ch) if Char is wchar_t. + static char_type toupper(char_type ch) + { + return detail::c_toupper(ch); + } + + /// Returns a string_type containing all the characters that compare equal + /// disregrarding case to the one passed in. This function can only be called + /// if has_fold_case<c_regex_traits<Char> >::value is true. + /// + /// \param ch The source character. + /// \return string_type containing all chars which are equal to ch when disregarding + /// case + //typedef array<char_type, 2> fold_case_type; + string_type fold_case(char_type ch) const + { + BOOST_MPL_ASSERT((is_same<char_type, char>)); + char_type ntcs[] = { + detail::c_tolower(ch) + , detail::c_toupper(ch) + , 0 + }; + if(ntcs[1] == ntcs[0]) + ntcs[1] = 0; + return string_type(ntcs); + } + + /// Checks to see if a character is within a character range. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return first <= ch && ch <= last. + static bool in_range(char_type first, char_type last, char_type ch) + { + return first <= ch && ch <= last; + } + + /// Checks to see if a character is within a character range, irregardless of case. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return in_range(first, last, ch) || in_range(first, last, tolower(ch)) || in_range(first, + /// last, toupper(ch)) + /// \attention The default implementation doesn't do proper Unicode + /// case folding, but this is the best we can do with the standard + /// C locale functions. + static bool in_range_nocase(char_type first, char_type last, char_type ch) + { + return c_regex_traits::in_range(first, last, ch) + || c_regex_traits::in_range(first, last, detail::c_tolower(ch)) + || c_regex_traits::in_range(first, last, detail::c_toupper(ch)); + } + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// then v.transform(G1, G2) < v.transform(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type transform(FwdIter begin, FwdIter end) + { + BOOST_ASSERT(false); // BUGBUG implement me + } + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// when character case is not considered then + /// v.transform_primary(G1, G2) < v.transform_primary(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type transform_primary(FwdIter begin, FwdIter end) + { + BOOST_ASSERT(false); // BUGBUG implement me + } + + /// Returns a sequence of characters that represents the collating element + /// consisting of the character sequence designated by the iterator range [F1, F2). + /// Returns an empty string if the character sequence is not a valid collating element. + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type lookup_collatename(FwdIter begin, FwdIter end) + { + BOOST_ASSERT(false); // BUGBUG implement me + } + + /// For the character class name represented by the specified character sequence, + /// return the corresponding bitmask representation. + /// + /// \param begin A forward iterator to the start of the character sequence representing + /// the name of the character class. + /// \param end The end of the character sequence. + /// \param icase Specifies whether the returned bitmask should represent the case-insensitive + /// version of the character class. + /// \return A bitmask representing the character class. + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + return detail::char_class_impl<char_type>::lookup_classname(begin, end, icase); + } + + /// Tests a character against a character class bitmask. + /// + /// \param ch The character to test. + /// \param mask The character class bitmask against which to test. + /// \pre mask is a bitmask returned by lookup_classname, or is several such masks bit-or'ed + /// together. + /// \return true if the character is a member of any of the specified character classes, false + /// otherwise. + static bool isctype(char_type ch, char_class_type mask) + { + return detail::char_class_impl<char_type>::isctype(ch, mask); + } + + /// Convert a digit character into the integer it represents. + /// + /// \param ch The digit character. + /// \param radix The radix to use for the conversion. + /// \pre radix is one of 8, 10, or 16. + /// \return -1 if ch is not a digit character, the integer value of the character otherwise. If + /// char_type is char, std::strtol is used for the conversion. If char_type is wchar_t, + /// std::wcstol is used. + static int value(char_type ch, int radix); + + /// No-op + /// + locale_type imbue(locale_type loc) + { + this->base_type::imbue(*this); + return loc; + } + + /// No-op + /// + static locale_type getloc() + { + locale_type loc; + return loc; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// c_regex_traits<>::widen specializations +/// INTERNAL ONLY +template<> +inline char c_regex_traits<char>::widen(char ch) +{ + return ch; +} + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/// INTERNAL ONLY +template<> +inline wchar_t c_regex_traits<wchar_t>::widen(char ch) +{ + using namespace std; + return btowc(ch); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// c_regex_traits<>::hash specializations +/// INTERNAL ONLY +template<> +inline unsigned char c_regex_traits<char>::hash(char ch) +{ + return static_cast<unsigned char>(ch); +} + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/// INTERNAL ONLY +template<> +inline unsigned char c_regex_traits<wchar_t>::hash(wchar_t ch) +{ + return static_cast<unsigned char>(ch); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// c_regex_traits<>::value specializations +/// INTERNAL ONLY +template<> +inline int c_regex_traits<char>::value(char ch, int radix) +{ + using namespace std; + BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix); + char begin[2] = { ch, '\0' }, *end = 0; + int val = strtol(begin, &end, radix); + return begin == end ? -1 : val; +} + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/// INTERNAL ONLY +template<> +inline int c_regex_traits<wchar_t>::value(wchar_t ch, int radix) +{ + using namespace std; + BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix); + wchar_t begin[2] = { ch, L'\0' }, *end = 0; + int val = wcstol(begin, &end, radix); + return begin == end ? -1 : val; +} +#endif + +// Narrow C traits has fold_case() member function. +template<> +struct has_fold_case<c_regex_traits<char> > + : mpl::true_ +{ +}; + +}} + +#endif diff --git a/boost/xpressive/traits/cpp_regex_traits.hpp b/boost/xpressive/traits/cpp_regex_traits.hpp new file mode 100644 index 0000000000..5d5c7fd0b1 --- /dev/null +++ b/boost/xpressive/traits/cpp_regex_traits.hpp @@ -0,0 +1,694 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file cpp_regex_traits.hpp +/// Contains the definition of the cpp_regex_traits\<\> template, which is a +/// wrapper for std::locale that can be used to customize the behavior of +/// static and dynamic regexes. +// +// 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_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <ios> +#include <string> +#include <locale> +#include <sstream> +#include <boost/config.hpp> +#include <boost/assert.hpp> +#include <boost/integer.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/utility/literals.hpp> + +// From John Maddock: +// Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow masks to be combined, for example: +// std::use_facet<std::ctype<wchar_t> >(locale()).is(std::ctype_base::lower|std::ctype_base::upper, L'a'); +// incorrectly returns false. +// NOTE: later version of the gcc define __GLIBCXX__, not __GLIBCPP__ +#if BOOST_WORKAROUND(__GLIBCPP__, != 0) +# define BOOST_XPRESSIVE_BUGGY_CTYPE_FACET +#endif + +namespace boost { namespace xpressive +{ + +namespace detail +{ + // define an unsigned integral typedef of the same size as std::ctype_base::mask + typedef boost::uint_t<sizeof(std::ctype_base::mask) * CHAR_BIT>::least umask_t; + BOOST_MPL_ASSERT_RELATION(sizeof(std::ctype_base::mask), ==, sizeof(umask_t)); + + // Calculate what the size of the umaskex_t type should be to fix the 3 extra bitmasks + // 11 char categories in ctype_base + // + 3 extra categories for xpressive + // = 14 total bits needed + int const umaskex_bits = (14 > (sizeof(umask_t) * CHAR_BIT)) ? 14 : sizeof(umask_t) * CHAR_BIT; + + // define an unsigned integral type with at least umaskex_bits + typedef boost::uint_t<umaskex_bits>::fast umaskex_t; + BOOST_MPL_ASSERT_RELATION(sizeof(umask_t), <=, sizeof(umaskex_t)); + + // cast a ctype mask to a umaskex_t + template<std::ctype_base::mask Mask> + struct mask_cast + { + BOOST_STATIC_CONSTANT(umaskex_t, value = static_cast<umask_t>(Mask)); + }; + + #ifdef __CYGWIN__ + // Work around a gcc warning on cygwin + template<> + struct mask_cast<std::ctype_base::print> + { + BOOST_MPL_ASSERT_RELATION('\227', ==, std::ctype_base::print); + BOOST_STATIC_CONSTANT(umaskex_t, value = 0227); + }; + #endif + + #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + template<std::ctype_base::mask Mask> + umaskex_t const mask_cast<Mask>::value; + #endif + + #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET + // an unsigned integer with the highest bit set + umaskex_t const highest_bit = static_cast<umaskex_t>(1) << (sizeof(umaskex_t) * CHAR_BIT - 1); + + /////////////////////////////////////////////////////////////////////////////// + // unused_mask + // find a bit in an int that isn't set + template<umaskex_t In, umaskex_t Out = highest_bit, bool Done = (0 == (Out & In))> + struct unused_mask + { + BOOST_MPL_ASSERT_RELATION(1, !=, Out); + BOOST_STATIC_CONSTANT(umaskex_t, value = (unused_mask<In, (Out >> 1)>::value)); + }; + + template<umaskex_t In, umaskex_t Out> + struct unused_mask<In, Out, true> + { + BOOST_STATIC_CONSTANT(umaskex_t, value = Out); + }; + + #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION + template<umaskex_t In, umaskex_t Out, bool Done> + umaskex_t const unused_mask<In, Out, Done>::value; + #endif + + umaskex_t const std_ctype_alnum = mask_cast<std::ctype_base::alnum>::value; + umaskex_t const std_ctype_alpha = mask_cast<std::ctype_base::alpha>::value; + umaskex_t const std_ctype_cntrl = mask_cast<std::ctype_base::cntrl>::value; + umaskex_t const std_ctype_digit = mask_cast<std::ctype_base::digit>::value; + umaskex_t const std_ctype_graph = mask_cast<std::ctype_base::graph>::value; + umaskex_t const std_ctype_lower = mask_cast<std::ctype_base::lower>::value; + umaskex_t const std_ctype_print = mask_cast<std::ctype_base::print>::value; + umaskex_t const std_ctype_punct = mask_cast<std::ctype_base::punct>::value; + umaskex_t const std_ctype_space = mask_cast<std::ctype_base::space>::value; + umaskex_t const std_ctype_upper = mask_cast<std::ctype_base::upper>::value; + umaskex_t const std_ctype_xdigit = mask_cast<std::ctype_base::xdigit>::value; + + // Reserve some bits for the implementation + #if defined(__GLIBCXX__) + umaskex_t const std_ctype_reserved = 0x8000; + #elif defined(_CPPLIB_VER) && defined(BOOST_WINDOWS) + umaskex_t const std_ctype_reserved = 0x8200; + #else + umaskex_t const std_ctype_reserved = 0; + #endif + + // Bitwise-or all the ctype masks together + umaskex_t const all_ctype_masks = std_ctype_reserved + | std_ctype_alnum | std_ctype_alpha | std_ctype_cntrl | std_ctype_digit + | std_ctype_graph | std_ctype_lower | std_ctype_print | std_ctype_punct + | std_ctype_space | std_ctype_upper | std_ctype_xdigit; + + // define a new mask for "underscore" ("word" == alnum | underscore) + umaskex_t const non_std_ctype_underscore = unused_mask<all_ctype_masks>::value; + + // define a new mask for "blank" + umaskex_t const non_std_ctype_blank = unused_mask<all_ctype_masks | non_std_ctype_underscore>::value; + + // define a new mask for "newline" + umaskex_t const non_std_ctype_newline = unused_mask<all_ctype_masks | non_std_ctype_underscore | non_std_ctype_blank>::value; + + #else + /////////////////////////////////////////////////////////////////////////////// + // Ugly work-around for buggy ctype facets. + umaskex_t const std_ctype_alnum = 1 << 0; + umaskex_t const std_ctype_alpha = 1 << 1; + umaskex_t const std_ctype_cntrl = 1 << 2; + umaskex_t const std_ctype_digit = 1 << 3; + umaskex_t const std_ctype_graph = 1 << 4; + umaskex_t const std_ctype_lower = 1 << 5; + umaskex_t const std_ctype_print = 1 << 6; + umaskex_t const std_ctype_punct = 1 << 7; + umaskex_t const std_ctype_space = 1 << 8; + umaskex_t const std_ctype_upper = 1 << 9; + umaskex_t const std_ctype_xdigit = 1 << 10; + umaskex_t const non_std_ctype_underscore = 1 << 11; + umaskex_t const non_std_ctype_blank = 1 << 12; + umaskex_t const non_std_ctype_newline = 1 << 13; + + static umaskex_t const std_masks[] = + { + mask_cast<std::ctype_base::alnum>::value + , mask_cast<std::ctype_base::alpha>::value + , mask_cast<std::ctype_base::cntrl>::value + , mask_cast<std::ctype_base::digit>::value + , mask_cast<std::ctype_base::graph>::value + , mask_cast<std::ctype_base::lower>::value + , mask_cast<std::ctype_base::print>::value + , mask_cast<std::ctype_base::punct>::value + , mask_cast<std::ctype_base::space>::value + , mask_cast<std::ctype_base::upper>::value + , mask_cast<std::ctype_base::xdigit>::value + }; + + inline int mylog2(umaskex_t i) + { + return "\0\0\1\0\2\0\0\0\3"[i & 0xf] + + "\0\4\5\0\6\0\0\0\7"[(i & 0xf0) >> 04] + + "\0\10\11\0\12\0\0\0\13"[(i & 0xf00) >> 010]; + } + #endif + + // convenient constant for the extra masks + umaskex_t const non_std_ctype_masks = non_std_ctype_underscore | non_std_ctype_blank | non_std_ctype_newline; + + /////////////////////////////////////////////////////////////////////////////// + // cpp_regex_traits_base + // BUGBUG this should be replaced with a regex facet that lets you query for + // an array of underscore characters and an array of line separator characters. + template<typename Char, std::size_t SizeOfChar = sizeof(Char)> + struct cpp_regex_traits_base + { + protected: + void imbue(std::locale const &) + { + } + + static bool is(std::ctype<Char> const &ct, Char ch, umaskex_t mask) + { + #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET + + if(ct.is((std::ctype_base::mask)(umask_t)mask, ch)) + { + return true; + } + + #else + + umaskex_t tmp = mask & ~non_std_ctype_masks; + for(umaskex_t i; 0 != (i = (tmp & (~tmp+1))); tmp &= ~i) + { + std::ctype_base::mask m = (std::ctype_base::mask)(umask_t)std_masks[mylog2(i)]; + if(ct.is(m, ch)) + { + return true; + } + } + + #endif + + return ((mask & non_std_ctype_blank) && cpp_regex_traits_base::is_blank(ch)) + || ((mask & non_std_ctype_underscore) && cpp_regex_traits_base::is_underscore(ch)) + || ((mask & non_std_ctype_newline) && cpp_regex_traits_base::is_newline(ch)); + } + + private: + static bool is_blank(Char ch) + { + BOOST_MPL_ASSERT_RELATION('\t', ==, L'\t'); + BOOST_MPL_ASSERT_RELATION(' ', ==, L' '); + return L' ' == ch || L'\t' == ch; + } + + static bool is_underscore(Char ch) + { + BOOST_MPL_ASSERT_RELATION('_', ==, L'_'); + return L'_' == ch; + } + + static bool is_newline(Char ch) + { + BOOST_MPL_ASSERT_RELATION('\r', ==, L'\r'); + BOOST_MPL_ASSERT_RELATION('\n', ==, L'\n'); + BOOST_MPL_ASSERT_RELATION('\f', ==, L'\f'); + return L'\r' == ch || L'\n' == ch || L'\f' == ch + || (1 < SizeOfChar && (0x2028u == ch || 0x2029u == ch || 0x85u == ch)); + } + }; + + #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET + + template<typename Char> + struct cpp_regex_traits_base<Char, 1> + { + protected: + void imbue(std::locale const &loc) + { + int i = 0; + Char allchars[UCHAR_MAX + 1]; + for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) + { + allchars[i] = static_cast<Char>(i); + } + + std::ctype<Char> const &ct = BOOST_USE_FACET(std::ctype<Char>, loc); + std::ctype_base::mask tmp[UCHAR_MAX + 1]; + ct.is(allchars, allchars + UCHAR_MAX + 1, tmp); + for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) + { + this->masks_[i] = static_cast<umask_t>(tmp[i]); + BOOST_ASSERT(0 == (this->masks_[i] & non_std_ctype_masks)); + } + + this->masks_[static_cast<unsigned char>('_')] |= non_std_ctype_underscore; + this->masks_[static_cast<unsigned char>(' ')] |= non_std_ctype_blank; + this->masks_[static_cast<unsigned char>('\t')] |= non_std_ctype_blank; + this->masks_[static_cast<unsigned char>('\n')] |= non_std_ctype_newline; + this->masks_[static_cast<unsigned char>('\r')] |= non_std_ctype_newline; + this->masks_[static_cast<unsigned char>('\f')] |= non_std_ctype_newline; + } + + bool is(std::ctype<Char> const &, Char ch, umaskex_t mask) const + { + return 0 != (this->masks_[static_cast<unsigned char>(ch)] & mask); + } + + private: + umaskex_t masks_[UCHAR_MAX + 1]; + }; + + #endif + +} // namespace detail + + +/////////////////////////////////////////////////////////////////////////////// +// cpp_regex_traits +// +/// \brief Encapsaulates a std::locale for use by the +/// basic_regex\<\> class template. +template<typename Char> +struct cpp_regex_traits + : detail::cpp_regex_traits_base<Char> +{ + typedef Char char_type; + typedef std::basic_string<char_type> string_type; + typedef std::locale locale_type; + typedef detail::umaskex_t char_class_type; + typedef regex_traits_version_2_tag version_tag; + typedef detail::cpp_regex_traits_base<Char> base_type; + + /// Initialize a cpp_regex_traits object to use the specified std::locale, + /// or the global std::locale if none is specified. + /// + cpp_regex_traits(locale_type const &loc = locale_type()) + : base_type() + , loc_() + { + this->imbue(loc); + } + + /// Checks two cpp_regex_traits objects for equality + /// + /// \return this->getloc() == that.getloc(). + bool operator ==(cpp_regex_traits<char_type> const &that) const + { + return this->loc_ == that.loc_; + } + + /// Checks two cpp_regex_traits objects for inequality + /// + /// \return this->getloc() != that.getloc(). + bool operator !=(cpp_regex_traits<char_type> const &that) const + { + return this->loc_ != that.loc_; + } + + /// Convert a char to a Char + /// + /// \param ch The source character. + /// \return std::use_facet\<std::ctype\<char_type\> \>(this->getloc()).widen(ch). + char_type widen(char ch) const + { + return this->ctype_->widen(ch); + } + + /// Returns a hash value for a Char in the range [0, UCHAR_MAX] + /// + /// \param ch The source character. + /// \return a value between 0 and UCHAR_MAX, inclusive. + static unsigned char hash(char_type ch) + { + return static_cast<unsigned char>(std::char_traits<Char>::to_int_type(ch)); + } + + /// No-op + /// + /// \param ch The source character. + /// \return ch + static char_type translate(char_type ch) + { + return ch; + } + + /// Converts a character to lower-case using the internally-stored std::locale. + /// + /// \param ch The source character. + /// \return std::tolower(ch, this->getloc()). + char_type translate_nocase(char_type ch) const + { + return this->ctype_->tolower(ch); + } + + /// Converts a character to lower-case using the internally-stored std::locale. + /// + /// \param ch The source character. + /// \return std::tolower(ch, this->getloc()). + char_type tolower(char_type ch) const + { + return this->ctype_->tolower(ch); + } + + /// Converts a character to upper-case using the internally-stored std::locale. + /// + /// \param ch The source character. + /// \return std::toupper(ch, this->getloc()). + char_type toupper(char_type ch) const + { + return this->ctype_->toupper(ch); + } + + /// Returns a string_type containing all the characters that compare equal + /// disregrarding case to the one passed in. This function can only be called + /// if has_fold_case\<cpp_regex_traits\<Char\> \>::value is true. + /// + /// \param ch The source character. + /// \return string_type containing all chars which are equal to ch when disregarding + /// case + string_type fold_case(char_type ch) const + { + BOOST_MPL_ASSERT((is_same<char_type, char>)); + char_type ntcs[] = { + this->ctype_->tolower(ch) + , this->ctype_->toupper(ch) + , 0 + }; + if(ntcs[1] == ntcs[0]) + ntcs[1] = 0; + return string_type(ntcs); + } + + /// Checks to see if a character is within a character range. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return first <= ch && ch <= last. + static bool in_range(char_type first, char_type last, char_type ch) + { + return first <= ch && ch <= last; + } + + /// Checks to see if a character is within a character range, irregardless of case. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return in_range(first, last, ch) || in_range(first, last, tolower(ch, this->getloc())) || + /// in_range(first, last, toupper(ch, this->getloc())) + /// \attention The default implementation doesn't do proper Unicode + /// case folding, but this is the best we can do with the standard + /// ctype facet. + bool in_range_nocase(char_type first, char_type last, char_type ch) const + { + // NOTE: this default implementation doesn't do proper Unicode + // case folding, but this is the best we can do with the standard + // std::ctype facet. + return this->in_range(first, last, ch) + || this->in_range(first, last, this->ctype_->toupper(ch)) + || this->in_range(first, last, this->ctype_->tolower(ch)); + } + + /// INTERNAL ONLY + //string_type transform(char_type const *begin, char_type const *end) const + //{ + // return this->collate_->transform(begin, end); + //} + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// then v.transform(G1, G2) \< v.transform(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + string_type transform(FwdIter begin, FwdIter end) const + { + //string_type str(begin, end); + //return this->transform(str.data(), str.data() + str.size()); + + BOOST_ASSERT(false); + return string_type(); + } + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// when character case is not considered then + /// v.transform_primary(G1, G2) \< v.transform_primary(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + string_type transform_primary(FwdIter begin, FwdIter end) const + { + BOOST_ASSERT(false); // TODO implement me + return string_type(); + } + + /// Returns a sequence of characters that represents the collating element + /// consisting of the character sequence designated by the iterator range [F1, F2). + /// Returns an empty string if the character sequence is not a valid collating element. + /// + /// \attention Not currently used + template<typename FwdIter> + string_type lookup_collatename(FwdIter begin, FwdIter end) const + { + BOOST_ASSERT(false); // TODO implement me + return string_type(); + } + + /// For the character class name represented by the specified character sequence, + /// return the corresponding bitmask representation. + /// + /// \param begin A forward iterator to the start of the character sequence representing + /// the name of the character class. + /// \param end The end of the character sequence. + /// \param icase Specifies whether the returned bitmask should represent the case-insensitive + /// version of the character class. + /// \return A bitmask representing the character class. + template<typename FwdIter> + char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) const + { + static detail::umaskex_t const icase_masks = + detail::std_ctype_lower | detail::std_ctype_upper; + + BOOST_ASSERT(begin != end); + char_class_type char_class = this->lookup_classname_impl_(begin, end); + if(0 == char_class) + { + // convert the string to lowercase + string_type classname(begin, end); + for(typename string_type::size_type i = 0, len = classname.size(); i < len; ++i) + { + classname[i] = this->translate_nocase(classname[i]); + } + char_class = this->lookup_classname_impl_(classname.begin(), classname.end()); + } + // erase case-sensitivity if icase==true + if(icase && 0 != (char_class & icase_masks)) + { + char_class |= icase_masks; + } + return char_class; + } + + /// Tests a character against a character class bitmask. + /// + /// \param ch The character to test. + /// \param mask The character class bitmask against which to test. + /// \pre mask is a bitmask returned by lookup_classname, or is several such masks bit-or'ed + /// together. + /// \return true if the character is a member of any of the specified character classes, false + /// otherwise. + bool isctype(char_type ch, char_class_type mask) const + { + return this->base_type::is(*this->ctype_, ch, mask); + } + + /// Convert a digit character into the integer it represents. + /// + /// \param ch The digit character. + /// \param radix The radix to use for the conversion. + /// \pre radix is one of 8, 10, or 16. + /// \return -1 if ch is not a digit character, the integer value of the character otherwise. + /// The conversion is performed by imbueing a std::stringstream with this-\>getloc(); + /// setting the radix to one of oct, hex or dec; inserting ch into the stream; and + /// extracting an int. + int value(char_type ch, int radix) const + { + BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix); + int val = -1; + std::basic_stringstream<char_type> str; + str.imbue(this->getloc()); + str << (8 == radix ? std::oct : (16 == radix ? std::hex : std::dec)); + str.put(ch); + str >> val; + return str.fail() ? -1 : val; + } + + /// Imbues *this with loc + /// + /// \param loc A std::locale. + /// \return the previous std::locale used by *this. + locale_type imbue(locale_type loc) + { + locale_type old_loc = this->loc_; + this->loc_ = loc; + this->ctype_ = &BOOST_USE_FACET(std::ctype<char_type>, this->loc_); + //this->collate_ = &BOOST_USE_FACET(std::collate<char_type>, this->loc_); + this->base_type::imbue(this->loc_); + return old_loc; + } + + /// Returns the current std::locale used by *this. + /// + locale_type getloc() const + { + return this->loc_; + } + +private: + + /////////////////////////////////////////////////////////////////////////////// + // char_class_pair + /// INTERNAL ONLY + struct char_class_pair + { + char_type const *class_name_; + char_class_type class_type_; + }; + + /////////////////////////////////////////////////////////////////////////////// + // char_class + /// INTERNAL ONLY + static char_class_pair const &char_class(std::size_t j) + { + static char_class_pair const s_char_class_map[] = + { + { BOOST_XPR_CSTR_(char_type, "alnum"), detail::std_ctype_alnum } + , { BOOST_XPR_CSTR_(char_type, "alpha"), detail::std_ctype_alpha } + , { BOOST_XPR_CSTR_(char_type, "blank"), detail::non_std_ctype_blank } + , { BOOST_XPR_CSTR_(char_type, "cntrl"), detail::std_ctype_cntrl } + , { BOOST_XPR_CSTR_(char_type, "d"), detail::std_ctype_digit } + , { BOOST_XPR_CSTR_(char_type, "digit"), detail::std_ctype_digit } + , { BOOST_XPR_CSTR_(char_type, "graph"), detail::std_ctype_graph } + , { BOOST_XPR_CSTR_(char_type, "lower"), detail::std_ctype_lower } + , { BOOST_XPR_CSTR_(char_type, "newline"),detail::non_std_ctype_newline } + , { BOOST_XPR_CSTR_(char_type, "print"), detail::std_ctype_print } + , { BOOST_XPR_CSTR_(char_type, "punct"), detail::std_ctype_punct } + , { BOOST_XPR_CSTR_(char_type, "s"), detail::std_ctype_space } + , { BOOST_XPR_CSTR_(char_type, "space"), detail::std_ctype_space } + , { BOOST_XPR_CSTR_(char_type, "upper"), detail::std_ctype_upper } + , { BOOST_XPR_CSTR_(char_type, "w"), detail::std_ctype_alnum | detail::non_std_ctype_underscore } + , { BOOST_XPR_CSTR_(char_type, "xdigit"), detail::std_ctype_xdigit } + , { 0, 0 } + }; + return s_char_class_map[j]; + } + + /////////////////////////////////////////////////////////////////////////////// + // lookup_classname_impl + /// INTERNAL ONLY + template<typename FwdIter> + static char_class_type lookup_classname_impl_(FwdIter begin, FwdIter end) + { + // find the classname + typedef cpp_regex_traits<Char> this_t; + for(std::size_t j = 0; 0 != this_t::char_class(j).class_name_; ++j) + { + if(this_t::compare_(this_t::char_class(j).class_name_, begin, end)) + { + return this_t::char_class(j).class_type_; + } + } + return 0; + } + + /// INTERNAL ONLY + template<typename FwdIter> + static bool compare_(char_type const *name, FwdIter begin, FwdIter end) + { + for(; *name && begin != end; ++name, ++begin) + { + if(*name != *begin) + { + return false; + } + } + return !*name && begin == end; + } + + locale_type loc_; + std::ctype<char_type> const *ctype_; + //std::collate<char_type> const *collate_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// cpp_regex_traits<>::hash specializations +template<> +inline unsigned char cpp_regex_traits<unsigned char>::hash(unsigned char ch) +{ + return ch; +} + +template<> +inline unsigned char cpp_regex_traits<char>::hash(char ch) +{ + return static_cast<unsigned char>(ch); +} + +template<> +inline unsigned char cpp_regex_traits<signed char>::hash(signed char ch) +{ + return static_cast<unsigned char>(ch); +} + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +template<> +inline unsigned char cpp_regex_traits<wchar_t>::hash(wchar_t ch) +{ + return static_cast<unsigned char>(ch); +} +#endif + +// Narrow C++ traits has fold_case() member function. +template<> +struct has_fold_case<cpp_regex_traits<char> > + : mpl::true_ +{ +}; + + +}} + +#endif diff --git a/boost/xpressive/traits/detail/c_ctype.hpp b/boost/xpressive/traits/detail/c_ctype.hpp new file mode 100644 index 0000000000..5ed5d97c78 --- /dev/null +++ b/boost/xpressive/traits/detail/c_ctype.hpp @@ -0,0 +1,841 @@ +/////////////////////////////////////////////////////////////////////////////// +// c_ctype.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_TRAITS_DETAIL_C_CTYPE_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_TRAITS_DETAIL_C_CTYPE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <cctype> +#include <cstring> +#include <boost/mpl/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +# include <cwchar> +# include <cwctype> +#endif + +namespace boost { namespace xpressive { namespace detail +{ + +/////////////////////////////////////////////////////////////////////////////// +// isnewline +// +inline bool isnewline(char ch) +{ + switch(ch) + { + case L'\n': case L'\r': case L'\f': + return true; + default: + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// iswnewline +// +inline bool iswnewline(wchar_t ch) +{ + switch(ch) + { + case L'\n': case L'\r': case L'\f': case 0x2028u: case 0x2029u: case 0x85u: + return true; + default: + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// classname_a +// +template<typename FwdIter> +inline std::string classname_a(FwdIter begin, FwdIter end) +{ + std::string name(begin, end); + for(std::size_t i = 0; i < name.size(); ++i) + { + using namespace std; + name[i] = static_cast<char>(tolower(static_cast<unsigned char>(name[i]))); + } + return name; +} + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// classname_w +// +template<typename FwdIter> +inline std::wstring classname_w(FwdIter begin, FwdIter end) +{ + std::wstring name(begin, end); + for(std::size_t i = 0; i < name.size(); ++i) + { + using namespace std; + name[i] = towlower(name[i]); + } + return name; +} +#endif + + + +/////////////////////////////////////////////////////////////////////////////// +// char_class_impl +// +template<typename Char> +struct char_class_impl; + + +#if defined(__QNXNTO__) + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef short char_class_type; + BOOST_MPL_ASSERT_RELATION(0x07FF, ==, (_XB|_XA|_XS|_BB|_CN|_DI|_LO|_PU|_SP|_UP|_XD)); + BOOST_STATIC_CONSTANT(short, char_class_underscore = 0x1000); + BOOST_STATIC_CONSTANT(short, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return _DI|_LO|_UP|_XA; + if(name == "alpha") return _LO|_UP|_XA; + if(name == "blank") return _SP|_XB; + if(name == "cntrl") return _BB; + if(name == "d") return _DI; + if(name == "digit") return _DI; + if(name == "graph") return _DI|_LO|_PU|_UP|_XA; + if(name == "lower") return icase ? (_LO|_UP) : _LO; + if(name == "newline") return char_class_newline; + if(name == "print") return _DI|_LO|_PU|_SP|_UP|_XA; + if(name == "punct") return _PU; + if(name == "s") return _CN|_SP|_XS; + if(name == "space") return _CN|_SP|_XS; + if(name == "upper") return icase ? (_UP|_LO) : _UP; + if(name == "w") return _DI|_LO|_UP|_XA|char_class_underscore; + if(name == "xdigit") return _XD; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + using namespace std; + if(0 != (_Getchrtype((unsigned char)ch) & mask)) + { + return true; + } + + switch(ch) + { + case '_': return 0 != (mask & char_class_underscore); + case '\n': case '\r': case '\f': return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef int char_class_type; + //BOOST_STATIC_CONSTANT(int, char_class_alnum = 0x0001); + BOOST_STATIC_CONSTANT(int, char_class_alpha = 0x0002); + BOOST_STATIC_CONSTANT(int, char_class_blank = 0x0004); + BOOST_STATIC_CONSTANT(int, char_class_cntrl = 0x0008); + BOOST_STATIC_CONSTANT(int, char_class_digit = 0x0010); + //BOOST_STATIC_CONSTANT(int, char_class_graph = 0x0020); + BOOST_STATIC_CONSTANT(int, char_class_lower = 0x0040); + //BOOST_STATIC_CONSTANT(int, char_class_print = 0x0080); + BOOST_STATIC_CONSTANT(int, char_class_punct = 0x0100); + BOOST_STATIC_CONSTANT(int, char_class_space = 0x0200); + BOOST_STATIC_CONSTANT(int, char_class_upper = 0x0400); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x0800); + BOOST_STATIC_CONSTANT(int, char_class_xdigit = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return char_class_alpha|char_class_digit; + if(name == L"alpha") return char_class_alpha; + if(name == L"blank") return char_class_blank; + if(name == L"cntrl") return char_class_cntrl; + if(name == L"d") return char_class_digit; + if(name == L"digit") return char_class_digit; + if(name == L"graph") return char_class_punct|char_class_alpha|char_class_digit; + if(name == L"lower") return icase ? (char_class_lower|char_class_upper) : char_class_lower; + if(name == L"newline") return char_class_newline; + if(name == L"print") return char_class_blank|char_class_punct|char_class_alpha|char_class_digit; + if(name == L"punct") return char_class_punct; + if(name == L"s") return char_class_space; + if(name == L"space") return char_class_space; + if(name == L"upper") return icase ? (char_class_upper|char_class_lower) : char_class_upper; + if(name == L"w") return char_class_alpha|char_class_digit|char_class_underscore; + if(name == L"xdigit") return char_class_xdigit; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + return ((char_class_alpha & mask) && iswalpha(ch)) + || ((char_class_blank & mask) && (L' ' == ch || L'\t' == ch)) // BUGBUG + || ((char_class_cntrl & mask) && iswcntrl(ch)) + || ((char_class_digit & mask) && iswdigit(ch)) + || ((char_class_lower & mask) && iswlower(ch)) + || ((char_class_newline & mask) && detail::iswnewline(ch)) + || ((char_class_punct & mask) && iswpunct(ch)) + || ((char_class_space & mask) && iswspace(ch)) + || ((char_class_upper & mask) && iswupper(ch)) + || ((char_class_underscore & mask) && L'_' == ch) + || ((char_class_xdigit & mask) && iswxdigit(ch)) + ; + } +}; +#endif + + +#elif defined(__MINGW32_VERSION) + + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef int char_class_type; + BOOST_MPL_ASSERT_RELATION(0x81FF, ==, (_ALPHA|_UPPER|_LOWER|_DIGIT|_SPACE|_PUNCT|_CONTROL|_BLANK|_HEX|_LEADBYTE)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return _ALPHA|_DIGIT; + if(name == "alpha") return _ALPHA; + if(name == "blank") return _BLANK; // this is ONLY space!!! + if(name == "cntrl") return _CONTROL; + if(name == "d") return _DIGIT; + if(name == "digit") return _DIGIT; + if(name == "graph") return _PUNCT|_ALPHA|_DIGIT; + if(name == "lower") return icase ? (_LOWER|_UPPER) : _LOWER; + if(name == "newline") return char_class_newline; + if(name == "print") return _BLANK|_PUNCT|_ALPHA|_DIGIT; + if(name == "punct") return _PUNCT; + if(name == "s") return _SPACE; + if(name == "space") return _SPACE; + if(name == "upper") return icase ? (_UPPER|_LOWER) : _UPPER; + if(name == "w") return _ALPHA|_DIGIT|char_class_underscore; + if(name == "xdigit") return _HEX; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + using namespace std; + if(0 != _isctype(static_cast<unsigned char>(ch), mask)) + { + return true; + } + + switch(ch) + { + case '\t': return 0 != (mask & _BLANK); + case '_': return 0 != (mask & char_class_underscore); + case '\n': case '\r': case '\f': return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef wctype_t char_class_type; + BOOST_MPL_ASSERT_RELATION(0x81FF, ==, (_ALPHA|_UPPER|_LOWER|_DIGIT|_SPACE|_PUNCT|_CONTROL|_BLANK|_HEX|_LEADBYTE)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return _ALPHA|_DIGIT; + if(name == L"alpha") return _ALPHA; + if(name == L"blank") return _BLANK; // this is ONLY space!!! + if(name == L"cntrl") return _CONTROL; + if(name == L"d") return _DIGIT; + if(name == L"digit") return _DIGIT; + if(name == L"graph") return _PUNCT|_ALPHA|_DIGIT; + if(name == L"lower") return icase ? (_LOWER|_UPPER) : _LOWER; + if(name == L"newline") return char_class_newline; + if(name == L"print") return _BLANK|_PUNCT|_ALPHA|_DIGIT; + if(name == L"punct") return _PUNCT; + if(name == L"s") return _SPACE; + if(name == L"space") return _SPACE; + if(name == L"upper") return icase ? (_UPPER|_LOWER) : _UPPER; + if(name == L"w") return _ALPHA|_DIGIT|char_class_underscore; + if(name == L"xdigit") return _HEX; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + if(0 != iswctype(ch, mask)) + { + return true; + } + + switch(ch) + { + case L'\t': return 0 != (mask & _BLANK); + case L'_': return 0 != (mask & char_class_underscore); + case L'\n': case L'\r': case L'\f': case 0x2028u: case 0x2029u: case 0x85u: + return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; +#endif + + +#elif defined(__CYGWIN__) + + + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef int char_class_type; + BOOST_MPL_ASSERT_RELATION(0377, ==, (_U|_L|_N|_S|_P|_C|_B|_X)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0400); + BOOST_STATIC_CONSTANT(int, char_class_newline = 01000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return _U|_L|_N; + if(name == "alpha") return _U|_L; + if(name == "blank") return _B; // BUGBUG what is this? + if(name == "cntrl") return _C; + if(name == "d") return _N; + if(name == "digit") return _N; + if(name == "graph") return _P|_U|_L|_N; + if(name == "lower") return icase ? (_L|_U) : _L; + if(name == "newline") return char_class_newline; + if(name == "print") return _B|_P|_U|_L|_N; + if(name == "punct") return _P; + if(name == "s") return _S; + if(name == "space") return _S; + if(name == "upper") return icase ? (_U|_L) : _U; + if(name == "w") return _U|_L|_N|char_class_underscore; + if(name == "xdigit") return _X; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + if(0 != static_cast<unsigned char>(((_ctype_+1)[(unsigned)(ch)]) & mask)) + { + return true; + } + + switch(ch) + { + case '_': return 0 != (mask & char_class_underscore); + case '\n': case '\r': case '\f': return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef int char_class_type; + //BOOST_STATIC_CONSTANT(int, char_class_alnum = 0x0001); + BOOST_STATIC_CONSTANT(int, char_class_alpha = 0x0002); + BOOST_STATIC_CONSTANT(int, char_class_blank = 0x0004); + BOOST_STATIC_CONSTANT(int, char_class_cntrl = 0x0008); + BOOST_STATIC_CONSTANT(int, char_class_digit = 0x0010); + //BOOST_STATIC_CONSTANT(int, char_class_graph = 0x0020); + BOOST_STATIC_CONSTANT(int, char_class_lower = 0x0040); + //BOOST_STATIC_CONSTANT(int, char_class_print = 0x0080); + BOOST_STATIC_CONSTANT(int, char_class_punct = 0x0100); + BOOST_STATIC_CONSTANT(int, char_class_space = 0x0200); + BOOST_STATIC_CONSTANT(int, char_class_upper = 0x0400); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x0800); + BOOST_STATIC_CONSTANT(int, char_class_xdigit = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return char_class_alpha|char_class_digit; + if(name == L"alpha") return char_class_alpha; + if(name == L"blank") return char_class_blank; + if(name == L"cntrl") return char_class_cntrl; + if(name == L"d") return char_class_digit; + if(name == L"digit") return char_class_digit; + if(name == L"graph") return char_class_punct|char_class_alpha|char_class_digit; + if(name == L"lower") return icase ? (char_class_lower|char_class_upper) : char_class_lower; + if(name == L"newline") return char_class_newline; + if(name == L"print") return char_class_blank|char_class_punct|char_class_alpha|char_class_digit; + if(name == L"punct") return char_class_punct; + if(name == L"s") return char_class_space; + if(name == L"space") return char_class_space; + if(name == L"upper") return icase ? (char_class_upper|char_class_lower) : char_class_upper; + if(name == L"w") return char_class_alpha|char_class_digit|char_class_underscore; + if(name == L"xdigit") return char_class_xdigit; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + return ((char_class_alpha & mask) && iswalpha(ch)) + || ((char_class_blank & mask) && (L' ' == ch || L'\t' == ch)) // BUGBUG + || ((char_class_cntrl & mask) && iswcntrl(ch)) + || ((char_class_digit & mask) && iswdigit(ch)) + || ((char_class_lower & mask) && iswlower(ch)) + || ((char_class_newline & mask) && detail::iswnewline(ch)) + || ((char_class_punct & mask) && iswpunct(ch)) + || ((char_class_space & mask) && iswspace(ch)) + || ((char_class_upper & mask) && iswupper(ch)) + || ((char_class_underscore & mask) && L'_' == ch) + || ((char_class_xdigit & mask) && iswxdigit(ch)) + ; + } +}; +#endif + + + +#elif defined(__GLIBC__) + + + + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef int char_class_type; + BOOST_MPL_ASSERT_RELATION(0xffff, ==, (_ISalnum|_ISalpha|_ISblank|_IScntrl|_ISdigit|_ISgraph| + _ISlower|_ISprint|_ISpunct|_ISspace|_ISupper|_ISxdigit|0xffff)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x00010000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x00020000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return _ISalnum; + if(name == "alpha") return _ISalpha; + if(name == "blank") return _ISblank; + if(name == "cntrl") return _IScntrl; + if(name == "d") return _ISdigit; + if(name == "digit") return _ISdigit; + if(name == "graph") return _ISgraph; + if(name == "lower") return icase ? (_ISlower|_ISupper) : _ISlower; + if(name == "print") return _ISprint; + if(name == "newline") return char_class_newline; + if(name == "punct") return _ISpunct; + if(name == "s") return _ISspace; + if(name == "space") return _ISspace; + if(name == "upper") return icase ? (_ISupper|_ISlower) : _ISupper; + if(name == "w") return _ISalnum|char_class_underscore; + if(name == "xdigit") return _ISxdigit; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + using namespace std; + if(0 != __isctype(static_cast<unsigned char>(ch), mask)) + { + return true; + } + + switch(ch) + { + case '_': return 0 != (mask & char_class_underscore); + case '\n': case '\r': case '\f': return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef int char_class_type; + //BOOST_STATIC_CONSTANT(int, char_class_alnum = 0x0001); + BOOST_STATIC_CONSTANT(int, char_class_alpha = 0x0002); + BOOST_STATIC_CONSTANT(int, char_class_blank = 0x0004); + BOOST_STATIC_CONSTANT(int, char_class_cntrl = 0x0008); + BOOST_STATIC_CONSTANT(int, char_class_digit = 0x0010); + //BOOST_STATIC_CONSTANT(int, char_class_graph = 0x0020); + BOOST_STATIC_CONSTANT(int, char_class_lower = 0x0040); + //BOOST_STATIC_CONSTANT(int, char_class_print = 0x0080); + BOOST_STATIC_CONSTANT(int, char_class_punct = 0x0100); + BOOST_STATIC_CONSTANT(int, char_class_space = 0x0200); + BOOST_STATIC_CONSTANT(int, char_class_upper = 0x0400); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x0800); + BOOST_STATIC_CONSTANT(int, char_class_xdigit = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return char_class_alpha|char_class_digit; + if(name == L"alpha") return char_class_alpha; + if(name == L"blank") return char_class_blank; + if(name == L"cntrl") return char_class_cntrl; + if(name == L"d") return char_class_digit; + if(name == L"digit") return char_class_digit; + if(name == L"graph") return char_class_punct|char_class_alpha|char_class_digit; + if(name == L"lower") return icase ? (char_class_lower|char_class_upper) : char_class_lower; + if(name == L"newline") return char_class_newline; + if(name == L"print") return char_class_blank|char_class_punct|char_class_alpha|char_class_digit; + if(name == L"punct") return char_class_punct; + if(name == L"s") return char_class_space; + if(name == L"space") return char_class_space; + if(name == L"upper") return icase ? (char_class_upper|char_class_lower) : char_class_upper; + if(name == L"w") return char_class_alpha|char_class_digit|char_class_underscore; + if(name == L"xdigit") return char_class_xdigit; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + return ((char_class_alpha & mask) && iswalpha(ch)) + || ((char_class_blank & mask) && (L' ' == ch || L'\t' == ch)) // BUGBUG + || ((char_class_cntrl & mask) && iswcntrl(ch)) + || ((char_class_digit & mask) && iswdigit(ch)) + || ((char_class_lower & mask) && iswlower(ch)) + || ((char_class_newline & mask) && detail::iswnewline(ch)) + || ((char_class_punct & mask) && iswpunct(ch)) + || ((char_class_space & mask) && iswspace(ch)) + || ((char_class_upper & mask) && iswupper(ch)) + || ((char_class_underscore & mask) && L'_' == ch) + || ((char_class_xdigit & mask) && iswxdigit(ch)) + ; + } +}; +#endif + + + +#elif defined(_CPPLIB_VER) // Dinkumware STL + + + + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef int char_class_type; + BOOST_MPL_ASSERT_RELATION(0x81FF, ==, (_ALPHA|_UPPER|_LOWER|_DIGIT|_SPACE|_PUNCT|_CONTROL|_BLANK|_HEX|_LEADBYTE)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return _ALPHA|_DIGIT; + if(name == "alpha") return _ALPHA; + if(name == "blank") return _BLANK; // this is ONLY space!!! + if(name == "cntrl") return _CONTROL; + if(name == "d") return _DIGIT; + if(name == "digit") return _DIGIT; + if(name == "graph") return _PUNCT|_ALPHA|_DIGIT; + if(name == "lower") return icase ? (_LOWER|_UPPER) : _LOWER; + if(name == "newline") return char_class_newline; + if(name == "print") return _BLANK|_PUNCT|_ALPHA|_DIGIT; + if(name == "punct") return _PUNCT; + if(name == "s") return _SPACE; + if(name == "space") return _SPACE; + if(name == "upper") return icase ? (_UPPER|_LOWER) : _UPPER; + if(name == "w") return _ALPHA|_DIGIT|char_class_underscore; + if(name == "xdigit") return _HEX; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + using namespace std; + if(0 != _isctype(static_cast<unsigned char>(ch), mask)) + { + return true; + } + + switch(ch) + { + case '\t': return 0 != (mask & _BLANK); + case '_': return 0 != (mask & char_class_underscore); + case '\n': case '\r': case '\f': return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef wctype_t char_class_type; + BOOST_MPL_ASSERT_RELATION(0x81FF, ==, (_ALPHA|_UPPER|_LOWER|_DIGIT|_SPACE|_PUNCT|_CONTROL|_BLANK|_HEX|_LEADBYTE)); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return _ALPHA|_DIGIT; + if(name == L"alpha") return _ALPHA; + if(name == L"blank") return _BLANK; // this is ONLY space!!! + if(name == L"cntrl") return _CONTROL; + if(name == L"d") return _DIGIT; + if(name == L"digit") return _DIGIT; + if(name == L"graph") return _PUNCT|_ALPHA|_DIGIT; + if(name == L"lower") return icase ? _LOWER|_UPPER : _LOWER; + if(name == L"newline") return char_class_newline; + if(name == L"print") return _BLANK|_PUNCT|_ALPHA|_DIGIT; + if(name == L"punct") return _PUNCT; + if(name == L"s") return _SPACE; + if(name == L"space") return _SPACE; + if(name == L"upper") return icase ? _UPPER|_LOWER : _UPPER; + if(name == L"w") return _ALPHA|_DIGIT|char_class_underscore; + if(name == L"xdigit") return _HEX; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + if(0 != iswctype(ch, mask)) + { + return true; + } + + switch(ch) + { + case L'\t': return 0 != (mask & _BLANK); + case L'_': return 0 != (mask & char_class_underscore); + case L'\n': case L'\r': case L'\f': case 0x2028u: case 0x2029u: case 0x85u: + return 0 != (mask & char_class_newline); + default:; + } + + return false; + } +}; +#endif + + + +#else // unknown, use portable implementation + + + + +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<char> +{ + typedef int char_class_type; + //BOOST_STATIC_CONSTANT(int, char_class_alnum = 0x0001); + BOOST_STATIC_CONSTANT(int, char_class_alpha = 0x0002); + BOOST_STATIC_CONSTANT(int, char_class_blank = 0x0004); + BOOST_STATIC_CONSTANT(int, char_class_cntrl = 0x0008); + BOOST_STATIC_CONSTANT(int, char_class_digit = 0x0010); + //BOOST_STATIC_CONSTANT(int, char_class_graph = 0x0020); + BOOST_STATIC_CONSTANT(int, char_class_lower = 0x0040); + //BOOST_STATIC_CONSTANT(int, char_class_print = 0x0080); + BOOST_STATIC_CONSTANT(int, char_class_punct = 0x0100); + BOOST_STATIC_CONSTANT(int, char_class_space = 0x0200); + BOOST_STATIC_CONSTANT(int, char_class_upper = 0x0400); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x0800); + BOOST_STATIC_CONSTANT(int, char_class_xdigit = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + string const name = classname_a(begin, end); + if(name == "alnum") return char_class_alpha|char_class_digit; + if(name == "alpha") return char_class_alpha; + if(name == "blank") return char_class_blank; + if(name == "cntrl") return char_class_cntrl; + if(name == "d") return char_class_digit; + if(name == "digit") return char_class_digit; + if(name == "graph") return char_class_punct|char_class_alpha|char_class_digit; + if(name == "lower") return icase ? (char_class_lower|char_class_upper) : char_class_lower; + if(name == "newline") return char_class_newline; + if(name == "print") return char_class_blank|char_class_punct|char_class_alpha|char_class_digit; + if(name == "punct") return char_class_punct; + if(name == "s") return char_class_space; + if(name == "space") return char_class_space; + if(name == "upper") return icase ? (char_class_upper|char_class_lower) : char_class_upper; + if(name == "w") return char_class_alpha|char_class_digit|char_class_underscore; + if(name == "xdigit") return char_class_xdigit; + return 0; + } + + static bool isctype(char ch, char_class_type mask) + { + using namespace std; + unsigned char uch = static_cast<unsigned char>(ch); + return ((char_class_alpha & mask) && isalpha(uch)) + || ((char_class_blank & mask) && (' ' == ch || '\t' == ch)) // BUGBUG + || ((char_class_cntrl & mask) && iscntrl(uch)) + || ((char_class_digit & mask) && isdigit(uch)) + || ((char_class_lower & mask) && islower(uch)) + || ((char_class_newline & mask) && detail::isnewline(ch)) + || ((char_class_punct & mask) && ispunct(uch)) + || ((char_class_space & mask) && isspace(uch)) + || ((char_class_upper & mask) && isupper(uch)) + || ((char_class_underscore & mask) && '_' == ch) + || ((char_class_xdigit & mask) && isxdigit(uch)) + ; + } +}; + +#ifndef BOOST_XPRESSIVE_NO_WREGEX +/////////////////////////////////////////////////////////////////////////////// +// +template<> +struct char_class_impl<wchar_t> +{ + typedef int char_class_type; + //BOOST_STATIC_CONSTANT(int, char_class_alnum = 0x0001); + BOOST_STATIC_CONSTANT(int, char_class_alpha = 0x0002); + BOOST_STATIC_CONSTANT(int, char_class_blank = 0x0004); + BOOST_STATIC_CONSTANT(int, char_class_cntrl = 0x0008); + BOOST_STATIC_CONSTANT(int, char_class_digit = 0x0010); + //BOOST_STATIC_CONSTANT(int, char_class_graph = 0x0020); + BOOST_STATIC_CONSTANT(int, char_class_lower = 0x0040); + //BOOST_STATIC_CONSTANT(int, char_class_print = 0x0080); + BOOST_STATIC_CONSTANT(int, char_class_punct = 0x0100); + BOOST_STATIC_CONSTANT(int, char_class_space = 0x0200); + BOOST_STATIC_CONSTANT(int, char_class_upper = 0x0400); + BOOST_STATIC_CONSTANT(int, char_class_underscore = 0x0800); + BOOST_STATIC_CONSTANT(int, char_class_xdigit = 0x1000); + BOOST_STATIC_CONSTANT(int, char_class_newline = 0x2000); + + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + using namespace std; + wstring const name = classname_w(begin, end); + if(name == L"alnum") return char_class_alpha|char_class_digit; + if(name == L"alpha") return char_class_alpha; + if(name == L"blank") return char_class_blank; + if(name == L"cntrl") return char_class_cntrl; + if(name == L"d") return char_class_digit; + if(name == L"digit") return char_class_digit; + if(name == L"graph") return char_class_punct|char_class_alpha|char_class_digit; + if(name == L"newline") return char_class_newline; + if(name == L"lower") return icase ? (char_class_lower|char_class_upper) : char_class_lower; + if(name == L"print") return char_class_blank|char_class_punct|char_class_alpha|char_class_digit; + if(name == L"punct") return char_class_punct; + if(name == L"s") return char_class_space; + if(name == L"space") return char_class_space; + if(name == L"upper") return icase ? (char_class_upper|char_class_lower) : char_class_upper; + if(name == L"w") return char_class_alpha|char_class_digit|char_class_underscore; + if(name == L"xdigit") return char_class_xdigit; + return 0; + } + + static bool isctype(wchar_t ch, char_class_type mask) + { + using namespace std; + return ((char_class_alpha & mask) && iswalpha(ch)) + || ((char_class_blank & mask) && (L' ' == ch || L'\t' == ch)) // BUGBUG + || ((char_class_cntrl & mask) && iswcntrl(ch)) + || ((char_class_digit & mask) && iswdigit(ch)) + || ((char_class_lower & mask) && iswlower(ch)) + || ((char_class_newline & mask) && detail::iswnewline(ch)) + || ((char_class_punct & mask) && iswpunct(ch)) + || ((char_class_space & mask) && iswspace(ch)) + || ((char_class_upper & mask) && iswupper(ch)) + || ((char_class_underscore & mask) && L'_' == ch) + || ((char_class_xdigit & mask) && iswxdigit(ch)) + ; + } +}; +#endif + + +#endif + + +}}} // namespace boost::xpressive::detail + +#endif diff --git a/boost/xpressive/traits/null_regex_traits.hpp b/boost/xpressive/traits/null_regex_traits.hpp new file mode 100644 index 0000000000..6892e88206 --- /dev/null +++ b/boost/xpressive/traits/null_regex_traits.hpp @@ -0,0 +1,231 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file null_regex_traits.hpp +/// Contains the definition of the null_regex_traits\<\> template, which is a +/// stub regex traits implementation that can be used by static and dynamic +/// regexes for searching non-character data. +// +// 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_TRAITS_NULL_REGEX_TRAITS_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_TRAITS_NULL_REGEX_TRAITS_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <vector> +#include <boost/assert.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> +#include <boost/xpressive/detail/utility/never_true.hpp> +#include <boost/xpressive/detail/utility/ignore_unused.hpp> + +namespace boost { namespace xpressive +{ + +namespace detail +{ + struct not_a_locale {}; +} + +struct regex_traits_version_1_tag; + +/////////////////////////////////////////////////////////////////////////////// +// null_regex_traits +// +/// \brief stub regex_traits for non-char data +/// +template<typename Elem> +struct null_regex_traits +{ + typedef Elem char_type; + typedef std::vector<char_type> string_type; + typedef detail::not_a_locale locale_type; + typedef int char_class_type; + typedef regex_traits_version_1_tag version_tag; + + /// Initialize a null_regex_traits object. + /// + null_regex_traits(locale_type = locale_type()) + { + } + + /// Checks two null_regex_traits objects for equality + /// + /// \return true. + bool operator ==(null_regex_traits<char_type> const &that) const + { + detail::ignore_unused(that); + return true; + } + + /// Checks two null_regex_traits objects for inequality + /// + /// \return false. + bool operator !=(null_regex_traits<char_type> const &that) const + { + detail::ignore_unused(that); + return false; + } + + /// Convert a char to a Elem + /// + /// \param ch The source character. + /// \return Elem(ch). + char_type widen(char ch) const + { + return char_type(ch); + } + + /// Returns a hash value for a Elem in the range [0, UCHAR_MAX] + /// + /// \param ch The source character. + /// \return a value between 0 and UCHAR_MAX, inclusive. + static unsigned char hash(char_type ch) + { + return static_cast<unsigned char>(ch); + } + + /// No-op + /// + /// \param ch The source character. + /// \return ch + static char_type translate(char_type ch) + { + return ch; + } + + /// No-op + /// + /// \param ch The source character. + /// \return ch + static char_type translate_nocase(char_type ch) + { + return ch; + } + + /// Checks to see if a character is within a character range. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return first <= ch && ch <= last. + static bool in_range(char_type first, char_type last, char_type ch) + { + return first <= ch && ch <= last; + } + + /// Checks to see if a character is within a character range. + /// + /// \param first The bottom of the range, inclusive. + /// \param last The top of the range, inclusive. + /// \param ch The source character. + /// \return first <= ch && ch <= last. + /// \attention Since the null_regex_traits does not do case-folding, + /// this function is equivalent to in_range(). + static bool in_range_nocase(char_type first, char_type last, char_type ch) + { + return first <= ch && ch <= last; + } + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// then v.transform(G1, G2) < v.transform(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type transform(FwdIter begin, FwdIter end) + { + return string_type(begin, end); + } + + /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) + /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) + /// when character case is not considered then + /// v.transform_primary(G1, G2) < v.transform_primary(H1, H2). + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type transform_primary(FwdIter begin, FwdIter end) + { + return string_type(begin, end); + } + + /// Returns a sequence of characters that represents the collating element + /// consisting of the character sequence designated by the iterator range [F1, F2). + /// Returns an empty string if the character sequence is not a valid collating element. + /// + /// \attention Not currently used + template<typename FwdIter> + static string_type lookup_collatename(FwdIter begin, FwdIter end) + { + detail::ignore_unused(begin); + detail::ignore_unused(end); + return string_type(); + } + + /// The null_regex_traits does not have character classifications, so lookup_classname() + /// is unused. + /// + /// \param begin not used + /// \param end not used + /// \param icase not used + /// \return static_cast\<char_class_type\>(0) + template<typename FwdIter> + static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) + { + detail::ignore_unused(begin); + detail::ignore_unused(end); + detail::ignore_unused(icase); + return 0; + } + + /// The null_regex_traits does not have character classifications, so isctype() + /// is unused. + /// + /// \param ch not used + /// \param mask not used + /// \return false + static bool isctype(char_type ch, char_class_type mask) + { + detail::ignore_unused(ch); + detail::ignore_unused(mask); + return false; + } + + /// The null_regex_traits recognizes no elements as digits, so value() is unused. + /// + /// \param ch not used + /// \param radix not used + /// \return -1 + static int value(char_type ch, int radix) + { + detail::ignore_unused(ch); + detail::ignore_unused(radix); + return -1; + } + + /// Not used + /// + /// \param loc not used + /// \return loc + static locale_type imbue(locale_type loc) + { + return loc; + } + + /// Returns locale_type(). + /// + /// \return locale_type() + static locale_type getloc() + { + return locale_type(); + } +}; + +}} + +#endif diff --git a/boost/xpressive/xpressive.hpp b/boost/xpressive/xpressive.hpp new file mode 100644 index 0000000000..03021bed5b --- /dev/null +++ b/boost/xpressive/xpressive.hpp @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file xpressive.hpp +/// Includes all of xpressive including support for both static and +/// dynamic regular expressions. +// +// 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_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/xpressive_static.hpp> +#include <boost/xpressive/xpressive_dynamic.hpp> + +#endif diff --git a/boost/xpressive/xpressive_dynamic.hpp b/boost/xpressive/xpressive_dynamic.hpp new file mode 100644 index 0000000000..6f0e4d0bad --- /dev/null +++ b/boost/xpressive/xpressive_dynamic.hpp @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file xpressive_dynamic.hpp +/// Includes everything you need to write and use dynamic regular expressions. +// +// 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_DYNAMIC_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_DYNAMIC_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/xpressive/regex_compiler.hpp> +#include <boost/xpressive/basic_regex.hpp> +#include <boost/xpressive/sub_match.hpp> +#include <boost/xpressive/match_results.hpp> +#include <boost/xpressive/regex_algorithms.hpp> +#include <boost/xpressive/regex_iterator.hpp> +#include <boost/xpressive/regex_token_iterator.hpp> + +#endif diff --git a/boost/xpressive/xpressive_fwd.hpp b/boost/xpressive/xpressive_fwd.hpp new file mode 100644 index 0000000000..00c8c61506 --- /dev/null +++ b/boost/xpressive/xpressive_fwd.hpp @@ -0,0 +1,243 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file xpressive_fwd.hpp +/// Forward declarations for all of xpressive's public data types. +// +// 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_XPRESSIVE_FWD_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_XPRESSIVE_FWD_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <string> +#include <boost/config.hpp> +#include <boost/version.hpp> +#include <boost/iterator/iterator_traits.hpp> + +#if BOOST_VERSION >= 103500 +# define BOOST_PROTO_FUSION_V2 +#endif + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +# error Sorry, xpressive requires a compiler that supports partial template specialization. +#endif + +#if defined(BOOST_NO_STD_LOCALE) & !defined(BOOST_XPRESSIVE_USE_C_TRAITS) +# define BOOST_XPRESSIVE_USE_C_TRAITS +#endif + +#if defined(BOOST_NO_CWCHAR) | defined(BOOST_NO_CWCTYPE) | defined(BOOST_NO_STD_WSTRING) +# ifndef BOOST_XPRESSIVE_NO_WREGEX +# define BOOST_XPRESSIVE_NO_WREGEX +# endif +#endif + +// Stack protection under MS Windows +// Config logic taken from boost/regex/config.hpp +#ifndef BOOST_XPRESSIVE_HAS_MS_STACK_GUARD +# if (defined(_WIN32) || defined(_WIN64) || defined(_WINCE)) \ + && !defined(__GNUC__) \ + && !(defined(__BORLANDC__) && (__BORLANDC__ >= 0x600)) \ + && !(defined(__MWERKS__) && (__MWERKS__ <= 0x3003)) +# define BOOST_XPRESSIVE_HAS_MS_STACK_GUARD 1 +# else +# define BOOST_XPRESSIVE_HAS_MS_STACK_GUARD 0 +# endif +#endif + +#include <boost/proto/proto_fwd.hpp> + +namespace boost { namespace xpressive +{ + + template<typename Char> + struct cpp_regex_traits; + + template<typename Char> + struct c_regex_traits; + + template<typename Elem> + struct null_regex_traits; + + namespace detail + { + template<typename Char> + struct default_regex_traits + { + #ifdef BOOST_XPRESSIVE_USE_C_TRAITS + typedef c_regex_traits<Char> type; + #else + typedef cpp_regex_traits<Char> type; + #endif + }; + + struct mark_placeholder; + typedef proto::expr<proto::tag::terminal, proto::term<mark_placeholder>, 0> basic_mark_tag; + + struct regex_domain; + + } // namespace detail + + struct mark_tag; + + typedef void const *regex_id_type; + + struct regex_error; + + struct regex_traits_version_1_tag; + + struct regex_traits_version_2_tag; + + // DEPRECATED + /// INTERNAL ONLY + /// + struct regex_traits_version_1_case_fold_tag; + + template<typename Trait> + struct has_fold_case; + + template<typename BidiIter> + struct basic_regex; + + template<typename BidiIter> + struct match_results; + + template<typename BidiIter> + struct regex_iterator; + + template<typename BidiIter> + struct regex_token_iterator; + + template<typename BidiIter> + struct regex_id_filter_predicate; + + template<typename BidiIter> + struct sub_match; + + template<typename RegexTraits> + struct compiler_traits; + + template<typename Char, typename Impl = typename detail::default_regex_traits<Char>::type> + struct regex_traits; + + template + < + typename BidiIter + , typename RegexTraits = regex_traits<typename iterator_value<BidiIter>::type> + , typename CompilerTraits = compiler_traits<RegexTraits> + > + struct regex_compiler; + + template<typename T> + struct value; + + template<typename T> + struct reference; + + template<typename T> + struct local; + + template<typename T, int I = 0, typename Dummy = proto::is_proto_expr> + struct placeholder; + + namespace op + { + struct at; + struct push; + struct push_back; + struct push_front; + struct pop; + struct pop_back; + struct pop_front; + struct front; + struct back; + struct top; + struct first; + struct second; + struct matched; + struct length; + struct str; + struct insert; + struct make_pair; + template<typename T> + struct as; + template<typename T> + struct static_cast_; + template<typename T> + struct dynamic_cast_; + template<typename T> + struct const_cast_; + template<typename T> + struct construct; + template<typename Except> + struct throw_; + struct unwrap_reference; + } + + /////////////////////////////////////////////////////////////////////////////// + // Common typedefs + // + typedef basic_regex<std::string::const_iterator> sregex; + typedef basic_regex<char const *> cregex; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef basic_regex<std::wstring::const_iterator> wsregex; + typedef basic_regex<wchar_t const *> wcregex; + #endif + + typedef sub_match<std::string::const_iterator> ssub_match; + typedef sub_match<char const *> csub_match; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef sub_match<std::wstring::const_iterator> wssub_match; + typedef sub_match<wchar_t const *> wcsub_match; + #endif + + typedef regex_compiler<std::string::const_iterator> sregex_compiler; + typedef regex_compiler<char const *> cregex_compiler; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef regex_compiler<std::wstring::const_iterator> wsregex_compiler; + typedef regex_compiler<wchar_t const *> wcregex_compiler; + #endif + + typedef regex_iterator<std::string::const_iterator> sregex_iterator; + typedef regex_iterator<char const *> cregex_iterator; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef regex_iterator<std::wstring::const_iterator> wsregex_iterator; + typedef regex_iterator<wchar_t const *> wcregex_iterator; + #endif + + typedef regex_token_iterator<std::string::const_iterator> sregex_token_iterator; + typedef regex_token_iterator<char const *> cregex_token_iterator; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef regex_token_iterator<std::wstring::const_iterator> wsregex_token_iterator; + typedef regex_token_iterator<wchar_t const *> wcregex_token_iterator; + #endif + + typedef match_results<std::string::const_iterator> smatch; + typedef match_results<char const *> cmatch; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef match_results<std::wstring::const_iterator> wsmatch; + typedef match_results<wchar_t const *> wcmatch; + #endif + + typedef regex_id_filter_predicate<std::string::const_iterator> sregex_id_filter_predicate; + typedef regex_id_filter_predicate<char const *> cregex_id_filter_predicate; + + #ifndef BOOST_XPRESSIVE_NO_WREGEX + typedef regex_id_filter_predicate<std::wstring::const_iterator> wsregex_id_filter_predicate; + typedef regex_id_filter_predicate<wchar_t const *> wcregex_id_filter_predicate; + #endif + +}} // namespace boost::xpressive + +#endif diff --git a/boost/xpressive/xpressive_static.hpp b/boost/xpressive/xpressive_static.hpp new file mode 100644 index 0000000000..e7695dfd55 --- /dev/null +++ b/boost/xpressive/xpressive_static.hpp @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file xpressive_static.hpp +/// Includes everything you need to write static regular expressions and use +/// them. +// +// 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_STATIC_HPP_EAN_10_04_2005 +#define BOOST_XPRESSIVE_STATIC_HPP_EAN_10_04_2005 + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#ifdef _MSC_VER +// inline aggressively +# pragma inline_recursion(on) // turn on inline recursion +# pragma inline_depth(255) // max inline depth +#endif + +#include <boost/xpressive/regex_primitives.hpp> +#include <boost/xpressive/basic_regex.hpp> +#include <boost/xpressive/sub_match.hpp> +#include <boost/xpressive/match_results.hpp> +#include <boost/xpressive/regex_algorithms.hpp> +#include <boost/xpressive/regex_iterator.hpp> +#include <boost/xpressive/regex_token_iterator.hpp> + +#endif diff --git a/boost/xpressive/xpressive_typeof.hpp b/boost/xpressive/xpressive_typeof.hpp new file mode 100644 index 0000000000..0be12986b9 --- /dev/null +++ b/boost/xpressive/xpressive_typeof.hpp @@ -0,0 +1,150 @@ +/////////////////////////////////////////////////////////////////////////////// +/// \file xpressive_typeof.hpp +/// Type registrations so that xpressive can be used with the Boost.Typeof library. +// +// 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_XPRESSIVE_TYPEOF_H +#define BOOST_XPRESSIVE_XPRESSIVE_TYPEOF_H + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/config.hpp> +#include <boost/typeof/typeof.hpp> +#ifndef BOOST_NO_STD_LOCALE +# include <boost/typeof/std/locale.hpp> +#endif +#include <boost/proto/proto_typeof.hpp> +#include <boost/xpressive/detail/detail_fwd.hpp> + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::mpl::bool_, (bool)) + +/////////////////////////////////////////////////////////////////////////////// +// Misc. +// +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::set_initializer) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::keeper_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::modifier_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::lookahead_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::lookbehind_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::check_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::mark_tag) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::word_begin) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::word_end) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::generic_quant_tag, (unsigned int)(unsigned int)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::basic_regex, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::word_boundary, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::value, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::reference, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::local, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::placeholder, (typename)(int)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::tracking_ptr, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::regex_impl, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::let_, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::action_arg, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::named_mark, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::sub_match, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::nested_results, (typename)) + +/////////////////////////////////////////////////////////////////////////////// +// Placeholders +// +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::mark_placeholder) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::posix_charset_placeholder) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::assert_bol_placeholder) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::assert_eol_placeholder) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::logical_newline_placeholder) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::self_placeholder) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::assert_word_placeholder, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::range_placeholder, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::attribute_placeholder, (typename)) + +/////////////////////////////////////////////////////////////////////////////// +// Matchers +// +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::epsilon_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::true_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::end_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::independent_end_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::any_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::assert_bos_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::assert_eos_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::mark_begin_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::mark_end_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::repeat_begin_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::alternate_end_matcher) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::attr_end_matcher) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::assert_bol_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::assert_eol_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::literal_matcher, (typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::string_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::charset_matcher, (typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::logical_newline_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::mark_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::repeat_end_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::alternate_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::optional_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::optional_mark_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::simple_repeat_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::regex_byref_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::regex_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::posix_charset_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::assert_word_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::range_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::keeper_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::lookahead_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::lookbehind_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::set_matcher, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::predicate_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::action_matcher, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::attr_matcher, (typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::attr_begin_matcher, (typename)) + +/////////////////////////////////////////////////////////////////////////////// +// Ops +// +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::push) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::push_back) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::pop) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::push_front) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::pop_back) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::pop_front) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::back) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::front) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::top) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::first) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::second) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::matched) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::length) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::str) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::insert) +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::op::make_pair) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::as, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::static_cast_, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::dynamic_cast_, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::const_cast_, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::construct, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::op::throw_, (typename)) + +/////////////////////////////////////////////////////////////////////////////// +// Modifiers +// +BOOST_TYPEOF_REGISTER_TYPE(boost::xpressive::detail::icase_modifier) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::detail::locale_modifier, (typename)) + +/////////////////////////////////////////////////////////////////////////////// +// Traits +// +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::null_regex_traits, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::cpp_regex_traits, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::c_regex_traits, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::xpressive::regex_traits, (typename)(typename)) + +#endif |