Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r55008 - in trunk/boost/spirit: home/qi/detail home/qi/nonterminal home/support home/support/iterators home/support/iterators/detail repository/home/qi
From: hartmut.kaiser_at_[hidden]
Date: 2009-07-17 23:35:25


Author: hkaiser
Date: 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
New Revision: 55008
URL: http://svn.boost.org/trac/boost/changeset/55008

Log:
Spirit: integrated multi_pass iterator with expectation points and error handling
Added:
   trunk/boost/spirit/home/support/multi_pass_wrapper.hpp (contents, props changed)
Text files modified:
   trunk/boost/spirit/home/qi/detail/expect_function.hpp | 11 +++++++
   trunk/boost/spirit/home/qi/nonterminal/error_handler.hpp | 61 ++++++++++++++++++++++++++++++++++++++-
   trunk/boost/spirit/home/support/iterators/detail/combine_policies.hpp | 10 +++++
   trunk/boost/spirit/home/support/iterators/multi_pass.hpp | 38 +++++++++++++++++++++++-
   trunk/boost/spirit/home/support/iterators/multi_pass_fwd.hpp | 26 +++++++++++++++++
   trunk/boost/spirit/repository/home/qi/flush_multi_pass.hpp | 18 -----------
   6 files changed, 142 insertions(+), 22 deletions(-)

Modified: trunk/boost/spirit/home/qi/detail/expect_function.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/detail/expect_function.hpp (original)
+++ trunk/boost/spirit/home/qi/detail/expect_function.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -8,6 +8,7 @@
 #define SPIRIT_EXPECT_FUNCTION_APR_29_2007_0558PM
 
 #include <boost/spirit/home/support/unused.hpp>
+#include <boost/spirit/home/support/multi_pass_wrapper.hpp>
 
 namespace boost { namespace spirit { namespace qi { namespace detail
 {
@@ -33,6 +34,11 @@
         template <typename Component, typename Attribute>
         bool operator()(Component const& component, Attribute& attr) const
         {
+ // if this is not the first component in the expect chain we
+ // need to flush any multi_pass iterator we might be acting on
+ if (!is_first)
+ spirit::traits::clear_queue(first);
+
             // if we are testing the first component in the sequence,
             // return true if the parser fails, if this not the first
             // component, throw exception if the parser fails
@@ -53,6 +59,11 @@
         template <typename Component>
         bool operator()(Component const& component) const
         {
+ // if this is not the first component in the expect chain we
+ // need to flush any multi_pass iterator we might be acting on
+ if (!is_first)
+ spirit::traits::clear_queue(first);
+
             // if we are testing the first component in the sequence,
             // return true if the parser fails, if this not the first
             // component, throw exception if the parser fails

Modified: trunk/boost/spirit/home/qi/nonterminal/error_handler.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/nonterminal/error_handler.hpp (original)
+++ trunk/boost/spirit/home/qi/nonterminal/error_handler.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -13,7 +13,9 @@
 
 #include <boost/spirit/home/qi/operator/expect.hpp>
 #include <boost/spirit/home/qi/nonterminal/rule.hpp>
+#include <boost/spirit/home/support/multi_pass_wrapper.hpp>
 #include <boost/function.hpp>
+#include <boost/assert.hpp>
 
 namespace boost { namespace spirit { namespace qi
 {
@@ -25,6 +27,42 @@
       , rethrow
     };
 
+ namespace detail
+ {
+ // Helper template allowing to manage the inhibit clear queue flag in
+ // a multi_pass iterator. This is the usual specialization used for
+ // anything but a multi_pass iterator.
+ template <typename Iterator, bool active>
+ struct reset_on_exit
+ {
+ reset_on_exit(Iterator& it) {}
+ };
+
+ // For 'retry' or 'fail' error handlers we need to inhibit the flushing
+ // of the internal multi_pass buffers which otherwise might happen at
+ // deterministic expectation points inside the encapsulated right hand
+ // side of rule.
+ template <typename Iterator>
+ struct reset_on_exit<Iterator, true>
+ {
+ reset_on_exit(Iterator& it)
+ : it_(it)
+ , inhibit_clear_queue_(spirit::traits::inhibit_clear_queue(it))
+ {
+ spirit::traits::inhibit_clear_queue(it_, true);
+ }
+
+ ~reset_on_exit()
+ {
+ // reset inhibit flag in multi_pass on exit
+ spirit::traits::inhibit_clear_queue(it_, inhibit_clear_queue_);
+ }
+
+ Iterator& it_;
+ bool inhibit_clear_queue_;
+ };
+ }
+
     template <
         typename Iterator, typename Context
       , typename Skipper, typename F, error_handler_result action
@@ -48,6 +86,11 @@
             Iterator& first, Iterator const& last
           , Context& context, Skipper const& skipper) const
         {
+ typedef qi::detail::reset_on_exit<Iterator
+ , traits::is_multi_pass<Iterator>::value &&
+ (action == retry || action == fail)> on_exit_type;
+
+ on_exit_type on_exit(first);
             while (true)
             {
                 try
@@ -71,10 +114,24 @@
                     params args(first, last, x.first, x.what);
                     f(args, context, r);
 
+ // The assertions below will fire if you are using a
+ // multi_pass as the underlying iterator, one of your error
+ // handlers forced to 'fail' or 'retry' its guarded rule,
+ // and the error handler has not been instantiated using
+ // either 'fail' or 'retry' in the first place. Please see
+ // the mutli_pass docs for more information.
                     switch (r)
                     {
- case fail: return false;
- case retry: continue;
+ case fail:
+ BOOST_ASSERT(
+ traits::is_multi_pass<Iterator>::value &&
+ action != retry && action != fail);
+ return false;
+ case retry:
+ BOOST_ASSERT(
+ traits::is_multi_pass<Iterator>::value &&
+ action != retry && action != fail);
+ continue;
                         case accept: return true;
                         case rethrow: throw x;
                     }

Modified: trunk/boost/spirit/home/support/iterators/detail/combine_policies.hpp
==============================================================================
--- trunk/boost/spirit/home/support/iterators/detail/combine_policies.hpp (original)
+++ trunk/boost/spirit/home/support/iterators/detail/combine_policies.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -460,7 +460,15 @@
             typedef multi_pass_shared<T, ownership_policy, checking_policy
               , input_policy, storage_policy> shared_base_type;
 
- explicit shared(T const& input) : shared_base_type(input) {}
+ explicit shared(T const& input)
+ : shared_base_type(input), inhibit_clear_queue_(false) {}
+
+ // This is needed for the correct implementation of expectation
+ // points. Normally expectation points flush any multi_pass
+ // iterator they may act on, but if the corresponding error handler
+ // is of type 'retry' no flushing of the internal buffers should be
+ // executed (even if explicitly requested).
+ bool inhibit_clear_queue_;
         };
     };
 

Modified: trunk/boost/spirit/home/support/iterators/multi_pass.hpp
==============================================================================
--- trunk/boost/spirit/home/support/iterators/multi_pass.hpp (original)
+++ trunk/boost/spirit/home/support/iterators/multi_pass.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -129,9 +129,19 @@
             return tmp;
         }
 
- void clear_queue()
+ void clear_queue(BOOST_SCOPED_ENUM(traits::clear_mode) mode =
+ traits::clear_mode::clear_if_enabled)
         {
- policies_base_type::clear_queue(*this);
+ if (mode == traits::clear_mode::clear_always || !inhibit_clear_queue())
+ policies_base_type::clear_queue(*this);
+ }
+ bool inhibit_clear_queue() const
+ {
+ return this->member->inhibit_clear_queue_;
+ }
+ void inhibit_clear_queue(bool flag)
+ {
+ this->member->inhibit_clear_queue_ = flag;
         }
 
         bool operator==(multi_pass const& y) const
@@ -211,6 +221,30 @@
         x.swap(y);
     }
 
+ // define special functions allowing to integrate any multi_pass iterator
+ // with expectation points
+ namespace traits
+ {
+ template <typename T, typename Policies>
+ void clear_queue(multi_pass<T, Policies>& mp
+ , BOOST_SCOPED_ENUM(traits::clear_mode) mode)
+ {
+ mp.clear_queue(mode);
+ }
+
+ template <typename T, typename Policies>
+ void inhibit_clear_queue(multi_pass<T, Policies>& mp, bool flag)
+ {
+ mp.inhibit_clear_queue(flag);
+ }
+
+ template <typename T, typename Policies>
+ bool inhibit_clear_queue(multi_pass<T, Policies>& mp)
+ {
+ return mp.inhibit_clear_queue();
+ }
+ }
+
 }} // namespace boost::spirit
 
 #endif

Modified: trunk/boost/spirit/home/support/iterators/multi_pass_fwd.hpp
==============================================================================
--- trunk/boost/spirit/home/support/iterators/multi_pass_fwd.hpp (original)
+++ trunk/boost/spirit/home/support/iterators/multi_pass_fwd.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -1,5 +1,6 @@
 /*=============================================================================
     Copyright (c) 2007 Tobias Schwinger
+ Copyright (c) 2001-2009 Hartmut Kaiser
     http://spirit.sourceforge.net/
 
     Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -9,6 +10,7 @@
 #define BOOST_SPIRIT_ITERATOR_MULTI_PASS_FWD_APR_18_2008_1102AM
 
 #include <cstddef>
+#include <boost/spirit/home/support/multi_pass_wrapper.hpp>
 
 namespace boost { namespace spirit {
 
@@ -63,5 +65,29 @@
 
 }} // namespace boost::spirit
 
+namespace boost { namespace spirit { namespace traits
+{
+ // declare special functions allowing to integrate any multi_pass iterator
+ // with expectation points
+
+ // multi_pass iterators require special handling (for the non-specialized
+ // versions of these functions see support/multi_pass_wrapper.hpp)
+ template <typename T, typename Policies>
+ void clear_queue(multi_pass<T, Policies>&
+ , BOOST_SCOPED_ENUM(clear_mode) mode = clear_mode::clear_if_enabled);
+
+ template <typename T, typename Policies>
+ void inhibit_clear_queue(multi_pass<T, Policies>&, bool);
+
+ template <typename T, typename Policies>
+ bool inhibit_clear_queue(multi_pass<T, Policies>&);
+
+ // Helper template to recognize a multi_pass iterator. This specialization
+ // will be instantiated for any multi_pass iterator.
+ template <typename T, typename Policies>
+ struct is_multi_pass<multi_pass<T, Policies> > : mpl::true_ {};
+
+}}}
+
 #endif
 

Added: trunk/boost/spirit/home/support/multi_pass_wrapper.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/home/support/multi_pass_wrapper.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -0,0 +1,47 @@
+// Copyright (c) 2001-2009 Hartmut Kaiser
+//
+// 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)
+
+#if !defined(BOOST_SPIRIT_ITERATOR_MULTI_PASS_WRAPPER_JUL_12_2009_0914PM)
+#define BOOST_SPIRIT_ITERATOR_MULTI_PASS_WRAPPER_JUL_12_2009_0914PM
+
+#include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp>
+
+namespace boost { namespace spirit { namespace traits
+{
+ // declare special functions allowing to integrate any multi_pass iterator
+ // with expectation points
+
+ // normal iterators require no special handling
+ BOOST_SCOPED_ENUM_START(clear_mode)
+ {
+ clear_if_enabled,
+ clear_always
+ };
+ BOOST_SCOPED_ENUM_END
+
+ template <typename Iterator>
+ void clear_queue(Iterator&
+ , BOOST_SCOPED_ENUM(clear_mode) mode = clear_mode::clear_if_enabled)
+ {}
+
+ template <typename Iterator>
+ void inhibit_clear_queue(Iterator&, bool)
+ {}
+
+ template <typename Iterator>
+ bool inhibit_clear_queue(Iterator&)
+ {
+ return false;
+ }
+
+ // Helper template to recognize a multi_pass iterator. This specialization
+ // will be instantiated for any non-multi_pass iterator.
+ template <typename Iterator>
+ struct is_multi_pass : mpl::false_ {};
+
+}}}
+
+#endif
+

Modified: trunk/boost/spirit/repository/home/qi/flush_multi_pass.hpp
==============================================================================
--- trunk/boost/spirit/repository/home/qi/flush_multi_pass.hpp (original)
+++ trunk/boost/spirit/repository/home/qi/flush_multi_pass.hpp 2009-07-17 23:35:24 EDT (Fri, 17 Jul 2009)
@@ -40,22 +40,6 @@
     using repository::flush_multi_pass_type;
     using repository::flush_multi_pass;
 
- namespace detail
- {
- // normal iterators require no special handling
- template <typename Iterator>
- void clear_queue(Iterator& it)
- {
- }
-
- // where a multi_pass has some means to clear the internal buffers
- template<typename T, typename Policies>
- void clear_queue(multi_pass<T, Policies>& it)
- {
- it.clear_queue();
- }
- }
-
     ///////////////////////////////////////////////////////////////////////////
     // for a flush_multi_pass_parser generated parser
     struct flush_multi_pass_parser
@@ -73,7 +57,7 @@
           , Context& context, Skipper const& skipper
           , Attribute& attr) const
         {
- repository::qi::detail::clear_queue(first);
+ spirit::traits::clear_queue(first, traits::clear_mode::clear_always);
             return true;
         }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk