error_handler.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. ==============================================================================*/
  6. #if !defined(BOOST_SPIRIT_ERROR_HANDLER_APRIL_29_2007_1042PM)
  7. #define BOOST_SPIRIT_ERROR_HANDLER_APRIL_29_2007_1042PM
  8. #if defined(_MSC_VER)
  9. #pragma once
  10. #endif
  11. #include <boost/spirit/home/qi/operator/expect.hpp>
  12. #include <boost/spirit/home/qi/nonterminal/rule.hpp>
  13. #include <boost/spirit/home/support/multi_pass_wrapper.hpp>
  14. #include <boost/function.hpp>
  15. #include <boost/assert.hpp>
  16. namespace boost { namespace spirit { namespace qi
  17. {
  18. enum error_handler_result
  19. {
  20. fail
  21. , retry
  22. , accept
  23. , rethrow
  24. };
  25. namespace detail
  26. {
  27. // Helper template allowing to manage the inhibit clear queue flag in
  28. // a multi_pass iterator. This is the usual specialization used for
  29. // anything but a multi_pass iterator.
  30. template <typename Iterator, bool active>
  31. struct reset_on_exit
  32. {
  33. reset_on_exit(Iterator&) {}
  34. };
  35. // For 'retry' or 'fail' error handlers we need to inhibit the flushing
  36. // of the internal multi_pass buffers which otherwise might happen at
  37. // deterministic expectation points inside the encapsulated right hand
  38. // side of rule.
  39. template <typename Iterator>
  40. struct reset_on_exit<Iterator, true>
  41. {
  42. reset_on_exit(Iterator& it)
  43. : it_(it)
  44. , inhibit_clear_queue_(spirit::traits::inhibit_clear_queue(it))
  45. {
  46. spirit::traits::inhibit_clear_queue(it_, true);
  47. }
  48. ~reset_on_exit()
  49. {
  50. // reset inhibit flag in multi_pass on exit
  51. spirit::traits::inhibit_clear_queue(it_, inhibit_clear_queue_);
  52. }
  53. Iterator& it_;
  54. bool inhibit_clear_queue_;
  55. };
  56. }
  57. template <
  58. typename Iterator, typename Context
  59. , typename Skipper, typename F, error_handler_result action
  60. >
  61. struct error_handler
  62. {
  63. typedef function<
  64. bool(Iterator& first, Iterator const& last
  65. , Context& context
  66. , Skipper const& skipper
  67. )>
  68. function_type;
  69. error_handler(function_type subject_, F f_)
  70. : subject(subject_)
  71. , f(f_)
  72. {
  73. }
  74. bool operator()(
  75. Iterator& first, Iterator const& last
  76. , Context& context, Skipper const& skipper) const
  77. {
  78. typedef qi::detail::reset_on_exit<Iterator
  79. , traits::is_multi_pass<Iterator>::value &&
  80. (action == retry || action == fail)> on_exit_type;
  81. on_exit_type on_exit(first);
  82. for(;;)
  83. {
  84. try
  85. {
  86. Iterator i = first;
  87. bool r = subject(i, last, context, skipper);
  88. if (r)
  89. first = i;
  90. return r;
  91. }
  92. catch (expectation_failure<Iterator> const& x)
  93. {
  94. typedef
  95. fusion::vector<
  96. Iterator&
  97. , Iterator const&
  98. , Iterator const&
  99. , info const&>
  100. params;
  101. error_handler_result r = action;
  102. params args(first, last, x.first, x.what_);
  103. f(args, context, r);
  104. // The assertions below will fire if you are using a
  105. // multi_pass as the underlying iterator, one of your error
  106. // handlers forced its guarded rule to 'fail' or 'retry',
  107. // and the error handler has not been instantiated using
  108. // either 'fail' or 'retry' in the first place. Please see
  109. // the multi_pass docs for more information.
  110. switch (r)
  111. {
  112. case fail:
  113. BOOST_ASSERT(
  114. !traits::is_multi_pass<Iterator>::value ||
  115. action == retry || action == fail);
  116. return false;
  117. case retry:
  118. BOOST_ASSERT(
  119. !traits::is_multi_pass<Iterator>::value ||
  120. action == retry || action == fail);
  121. continue;
  122. case accept: return true;
  123. case rethrow: boost::throw_exception(x);
  124. }
  125. }
  126. }
  127. return false;
  128. }
  129. function_type subject;
  130. F f;
  131. };
  132. template <
  133. error_handler_result action
  134. , typename Iterator, typename T0, typename T1, typename T2
  135. , typename F>
  136. void on_error(rule<Iterator, T0, T1, T2>& r, F f)
  137. {
  138. typedef rule<Iterator, T0, T1, T2> rule_type;
  139. typedef
  140. error_handler<
  141. Iterator
  142. , typename rule_type::context_type
  143. , typename rule_type::skipper_type
  144. , F
  145. , action>
  146. error_handler;
  147. r.f = error_handler(r.f, f);
  148. }
  149. // Error handling support when <action> is not
  150. // specified. We will default to <fail>.
  151. template <typename Iterator, typename T0, typename T1
  152. , typename T2, typename F>
  153. void on_error(rule<Iterator, T0, T1, T2>& r, F f)
  154. {
  155. on_error<fail>(r, f);
  156. }
  157. }}}
  158. #endif