Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / spirit / home / x3 / nonterminal / detail / rule.hpp
1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3
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
9
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>
18
19 #if defined(BOOST_SPIRIT_X3_DEBUG)
20 #include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
21 #endif
22
23 #include <type_traits>
24
25 namespace boost { namespace spirit { namespace x3
26 {
27     template <typename ID>
28     struct identity;
29
30     template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
31     struct rule;
32
33     struct parse_pass_context_tag;
34
35     namespace detail
36     {
37         // we use this so we can detect if the default parse_rule
38         // is the being called.
39         struct default_parse_rule_result
40         {
41             default_parse_rule_result(bool r)
42               : r(r) {}
43             operator bool() const { return r; }
44             bool r;
45         };
46     }
47
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
52     parse_rule(
53         rule<ID, Attribute> rule_
54       , Iterator& first, Iterator const& last
55       , Context const& context, ActualAttribute& attr);
56 }}}
57
58 namespace boost { namespace spirit { namespace x3 { namespace detail
59 {
60 #if defined(BOOST_SPIRIT_X3_DEBUG)
61     template <typename Iterator, typename Attribute>
62     struct context_debug
63     {
64         context_debug(
65             char const* rule_name
66           , Iterator const& first, Iterator const& last
67           , Attribute const& attr
68           , bool const& ok_parse //was parse successful?
69           )
70           : ok_parse(ok_parse), rule_name(rule_name)
71           , first(first), last(last)
72           , attr(attr)
73           , f(detail::get_simple_trace())
74         {
75             f(first, last, attr, pre_parse, rule_name);
76         }
77
78         ~context_debug()
79         {
80             auto status = ok_parse ? successful_parse : failed_parse ;
81             f(first, last, attr, status, rule_name);
82         }
83
84         bool const& ok_parse;
85         char const* rule_name;
86         Iterator const& first;
87         Iterator const& last;
88         Attribute const& attr;
89         detail::simple_trace_type& f;
90     };
91 #endif
92
93     template <typename ID, typename Iterator, typename Context, typename Enable = void>
94     struct has_on_error : mpl::false_ {};
95
96     template <typename ID, typename Iterator, typename Context>
97     struct has_on_error<ID, Iterator, Context,
98         typename disable_if_substitution_failure<
99             decltype(
100                 std::declval<ID>().on_error(
101                     std::declval<Iterator&>()
102                   , std::declval<Iterator>()
103                   , std::declval<expectation_failure<Iterator>>()
104                   , std::declval<Context>()
105                 )
106             )>::type
107         >
108       : mpl::true_
109     {};
110
111     template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
112     struct has_on_success : mpl::false_ {};
113
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<
117             decltype(
118                 std::declval<ID>().on_success(
119                     std::declval<Iterator&>()
120                   , std::declval<Iterator>()
121                   , std::declval<Attribute&>()
122                   , std::declval<Context>()
123                 )
124             )>::type
125         >
126       : mpl::true_
127     {};
128
129     template <typename ID>
130     struct make_id
131     {
132         typedef identity<ID> type;
133     };
134
135     template <typename ID>
136     struct make_id<identity<ID>>
137     {
138         typedef identity<ID> type;
139     };
140
141     template <typename ID, typename RHS, typename Context>
142     Context const&
143     make_rule_context(RHS const& /* rhs */, Context const& context
144       , mpl::false_ /* is_default_parse_rule */)
145     {
146         return context;
147     }
148
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 */ )
152     {
153         return make_unique_context<ID>(rhs, context);
154     }
155
156     template <typename Attribute, typename ID>
157     struct rule_parser
158     {
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 */ )
164         {
165             return true;
166         }
167
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 */)
173         {
174             bool pass = true;
175             ID().on_success(
176                 first
177               , last
178               , attr
179               , make_context<parse_pass_context_tag>(pass, context)
180             );
181             return pass;
182         }
183
184         template <typename RHS, typename Iterator, typename Context
185           , typename RContext, typename ActualAttribute>
186         static bool parse_rhs_main(
187             RHS const& rhs
188           , Iterator& first, Iterator const& last
189           , Context const& context, RContext& rcontext, ActualAttribute& attr
190           , mpl::false_)
191         {
192             // see if the user has a BOOST_SPIRIT_DEFINE for this rule
193             typedef
194                 decltype(parse_rule(
195                     rule<ID, Attribute>(), first, last
196                   , make_unique_context<ID>(rhs, context), std::declval<Attribute&>()))
197             parse_rule_result;
198
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.
203             typedef
204                 is_same<parse_rule_result, default_parse_rule_result>
205             is_default_parse_rule;
206
207             Iterator i = first;
208             bool r = rhs.parse(
209                 i
210               , last
211               , make_rule_context<ID>(rhs, context, is_default_parse_rule())
212               , rcontext
213               , attr
214             );
215
216             if (r)
217             {
218                 auto first_ = first;
219                 x3::skip_over(first_, last, context);
220                 r = call_on_success(first_, i, context, attr
221                   , has_on_success<ID, Iterator, Context, ActualAttribute>());
222             }
223
224             if (r)
225                 first = i;
226             return r;
227         }
228
229         template <typename RHS, typename Iterator, typename Context
230           , typename RContext, typename ActualAttribute>
231         static bool parse_rhs_main(
232             RHS const& rhs
233           , Iterator& first, Iterator const& last
234           , Context const& context, RContext& rcontext, ActualAttribute& attr
235           , mpl::true_ /* on_error is found */)
236         {
237             for (;;)
238             {
239                 try
240                 {
241                     return parse_rhs_main(
242                         rhs, first, last, context, rcontext, attr, mpl::false_());
243                 }
244                 catch (expectation_failure<Iterator> const& x)
245                 {
246                     switch (ID().on_error(first, last, x, context))
247                     {
248                         case error_handler_result::fail:
249                             return false;
250                         case error_handler_result::retry:
251                             continue;
252                         case error_handler_result::accept:
253                             return true;
254                         case error_handler_result::rethrow:
255                             throw;
256                     }
257                 }
258             }
259         }
260
261         template <typename RHS, typename Iterator
262           , typename Context, typename RContext, typename ActualAttribute>
263         static bool parse_rhs_main(
264             RHS const& rhs
265           , Iterator& first, Iterator const& last
266           , Context const& context, RContext& rcontext, ActualAttribute& attr)
267         {
268             return parse_rhs_main(
269                 rhs, first, last, context, rcontext, attr
270               , has_on_error<ID, Iterator, Context>()
271             );
272         }
273
274         template <typename RHS, typename Iterator
275           , typename Context, typename RContext, typename ActualAttribute>
276         static bool parse_rhs(
277             RHS const& rhs
278           , Iterator& first, Iterator const& last
279           , Context const& context, RContext& rcontext, ActualAttribute& attr
280           , mpl::false_)
281         {
282             return parse_rhs_main(rhs, first, last, context, rcontext, attr);
283         }
284
285         template <typename RHS, typename Iterator
286           , typename Context, typename RContext, typename ActualAttribute>
287         static bool parse_rhs(
288             RHS const& rhs
289           , Iterator& first, Iterator const& last
290           , Context const& context, RContext& rcontext, ActualAttribute& /* attr */
291           , mpl::true_)
292         {
293             return parse_rhs_main(rhs, first, last, context, rcontext, unused);
294         }
295
296         template <typename RHS, typename Iterator, typename Context
297           , typename ActualAttribute, typename ExplicitAttrPropagation>
298         static bool call_rule_definition(
299             RHS const& rhs
300           , char const* rule_name
301           , Iterator& first, Iterator const& last
302           , Context const& context, ActualAttribute& attr
303           , ExplicitAttrPropagation)
304         {
305             boost::ignore_unused(rule_name);
306
307             // do down-stream transformation, provides attribute for
308             // rhs parser
309             typedef traits::transform_attribute<
310                 ActualAttribute, Attribute, parser_id>
311             transform;
312
313             typedef typename transform::type transform_attr;
314             transform_attr attr_ = transform::pre(attr);
315
316             bool ok_parse
317               //Creates a place to hold the result of parse_rhs
318               //called inside the following scope.
319               ;
320             {
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);
330 #endif
331                 ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
332                    , mpl::bool_
333                      < (  RHS::has_action
334                        && !ExplicitAttrPropagation::value
335                        )
336                      >()
337                   );
338             }
339             if (ok_parse)
340             {
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_));
344             }
345             return ok_parse;
346         }
347     };
348 }}}}
349
350 #endif