1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #if !defined(BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM)
8 #define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM
10 #include <boost/core/ignore_unused.hpp>
11 #include <boost/spirit/home/x3/auxiliary/guard.hpp>
12 #include <boost/spirit/home/x3/core/parser.hpp>
13 #include <boost/spirit/home/x3/core/skip_over.hpp>
14 #include <boost/spirit/home/x3/directive/expect.hpp>
15 #include <boost/spirit/home/x3/support/utility/sfinae.hpp>
16 #include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
17 #include <boost/utility/addressof.hpp>
19 #if defined(BOOST_SPIRIT_X3_DEBUG)
20 #include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
23 #include <type_traits>
25 namespace boost { namespace spirit { namespace x3
27 template <typename ID>
30 template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
33 struct parse_pass_context_tag;
37 // we use this so we can detect if the default parse_rule
38 // is the being called.
39 struct default_parse_rule_result
41 default_parse_rule_result(bool r)
43 operator bool() const { return r; }
48 // default parse_rule implementation
49 template <typename ID, typename Attribute, typename Iterator
50 , typename Context, typename ActualAttribute>
51 inline detail::default_parse_rule_result
53 rule<ID, Attribute> rule_
54 , Iterator& first, Iterator const& last
55 , Context const& context, ActualAttribute& attr);
58 namespace boost { namespace spirit { namespace x3 { namespace detail
60 #if defined(BOOST_SPIRIT_X3_DEBUG)
61 template <typename Iterator, typename Attribute>
66 , Iterator const& first, Iterator const& last
67 , Attribute const& attr
68 , bool const& ok_parse //was parse successful?
70 : ok_parse(ok_parse), rule_name(rule_name)
71 , first(first), last(last)
73 , f(detail::get_simple_trace())
75 f(first, last, attr, pre_parse, rule_name);
80 auto status = ok_parse ? successful_parse : failed_parse ;
81 f(first, last, attr, status, rule_name);
85 char const* rule_name;
86 Iterator const& first;
88 Attribute const& attr;
89 detail::simple_trace_type& f;
93 template <typename ID, typename Iterator, typename Context, typename Enable = void>
94 struct has_on_error : mpl::false_ {};
96 template <typename ID, typename Iterator, typename Context>
97 struct has_on_error<ID, Iterator, Context,
98 typename disable_if_substitution_failure<
100 std::declval<ID>().on_error(
101 std::declval<Iterator&>()
102 , std::declval<Iterator>()
103 , std::declval<expectation_failure<Iterator>>()
104 , std::declval<Context>()
111 template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
112 struct has_on_success : mpl::false_ {};
114 template <typename ID, typename Iterator, typename Attribute, typename Context>
115 struct has_on_success<ID, Iterator, Context, Attribute,
116 typename disable_if_substitution_failure<
118 std::declval<ID>().on_success(
119 std::declval<Iterator&>()
120 , std::declval<Iterator>()
121 , std::declval<Attribute&>()
122 , std::declval<Context>()
129 template <typename ID>
132 typedef identity<ID> type;
135 template <typename ID>
136 struct make_id<identity<ID>>
138 typedef identity<ID> type;
141 template <typename ID, typename RHS, typename Context>
143 make_rule_context(RHS const& /* rhs */, Context const& context
144 , mpl::false_ /* is_default_parse_rule */)
149 template <typename ID, typename RHS, typename Context>
150 auto make_rule_context(RHS const& rhs, Context const& context
151 , mpl::true_ /* is_default_parse_rule */ )
153 return make_unique_context<ID>(rhs, context);
156 template <typename Attribute, typename ID>
159 template <typename Iterator, typename Context, typename ActualAttribute>
160 static bool call_on_success(
161 Iterator& /* first */, Iterator const& /* last */
162 , Context const& /* context */, ActualAttribute& /* attr */
163 , mpl::false_ /* No on_success handler */ )
168 template <typename Iterator, typename Context, typename ActualAttribute>
169 static bool call_on_success(
170 Iterator& first, Iterator const& last
171 , Context const& context, ActualAttribute& attr
172 , mpl::true_ /* Has on_success handler */)
179 , make_context<parse_pass_context_tag>(pass, context)
184 template <typename RHS, typename Iterator, typename Context
185 , typename RContext, typename ActualAttribute>
186 static bool parse_rhs_main(
188 , Iterator& first, Iterator const& last
189 , Context const& context, RContext& rcontext, ActualAttribute& attr
192 // see if the user has a BOOST_SPIRIT_DEFINE for this rule
195 rule<ID, Attribute>(), first, last
196 , make_unique_context<ID>(rhs, context), std::declval<Attribute&>()))
199 // If there is no BOOST_SPIRIT_DEFINE for this rule,
200 // we'll make a context for this rule tagged by its ID
201 // so we can extract the rule later on in the default
202 // (generic) parse_rule function.
204 is_same<parse_rule_result, default_parse_rule_result>
205 is_default_parse_rule;
211 , make_rule_context<ID>(rhs, context, is_default_parse_rule())
219 x3::skip_over(first_, last, context);
220 r = call_on_success(first_, i, context, attr
221 , has_on_success<ID, Iterator, Context, ActualAttribute>());
229 template <typename RHS, typename Iterator, typename Context
230 , typename RContext, typename ActualAttribute>
231 static bool parse_rhs_main(
233 , Iterator& first, Iterator const& last
234 , Context const& context, RContext& rcontext, ActualAttribute& attr
235 , mpl::true_ /* on_error is found */)
241 return parse_rhs_main(
242 rhs, first, last, context, rcontext, attr, mpl::false_());
244 catch (expectation_failure<Iterator> const& x)
246 switch (ID().on_error(first, last, x, context))
248 case error_handler_result::fail:
250 case error_handler_result::retry:
252 case error_handler_result::accept:
254 case error_handler_result::rethrow:
261 template <typename RHS, typename Iterator
262 , typename Context, typename RContext, typename ActualAttribute>
263 static bool parse_rhs_main(
265 , Iterator& first, Iterator const& last
266 , Context const& context, RContext& rcontext, ActualAttribute& attr)
268 return parse_rhs_main(
269 rhs, first, last, context, rcontext, attr
270 , has_on_error<ID, Iterator, Context>()
274 template <typename RHS, typename Iterator
275 , typename Context, typename RContext, typename ActualAttribute>
276 static bool parse_rhs(
278 , Iterator& first, Iterator const& last
279 , Context const& context, RContext& rcontext, ActualAttribute& attr
282 return parse_rhs_main(rhs, first, last, context, rcontext, attr);
285 template <typename RHS, typename Iterator
286 , typename Context, typename RContext, typename ActualAttribute>
287 static bool parse_rhs(
289 , Iterator& first, Iterator const& last
290 , Context const& context, RContext& rcontext, ActualAttribute& /* attr */
293 return parse_rhs_main(rhs, first, last, context, rcontext, unused);
296 template <typename RHS, typename Iterator, typename Context
297 , typename ActualAttribute, typename ExplicitAttrPropagation>
298 static bool call_rule_definition(
300 , char const* rule_name
301 , Iterator& first, Iterator const& last
302 , Context const& context, ActualAttribute& attr
303 , ExplicitAttrPropagation)
305 boost::ignore_unused(rule_name);
307 // do down-stream transformation, provides attribute for
309 typedef traits::transform_attribute<
310 ActualAttribute, Attribute, parser_id>
313 typedef typename transform::type transform_attr;
314 transform_attr attr_ = transform::pre(attr);
317 //Creates a place to hold the result of parse_rhs
318 //called inside the following scope.
321 // Create a scope to cause the dbg variable below (within
322 // the #if...#endif) to call it's DTOR before any
323 // modifications are made to the attribute, attr_ passed
324 // to parse_rhs (such as might be done in
325 // transform::post when, for example,
326 // ActualAttribute is a recursive variant).
327 #if defined(BOOST_SPIRIT_X3_DEBUG)
328 context_debug<Iterator, transform_attr>
329 dbg(rule_name, first, last, attr_, ok_parse);
331 ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
334 && !ExplicitAttrPropagation::value
341 // do up-stream transformation, this integrates the results
342 // back into the original attribute value, if appropriate
343 transform::post(attr, std::forward<transform_attr>(attr_));