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/nonterminal/detail/transform_attribute.hpp>
16#include <boost/utility/addressof.hpp>
17
18#if defined(BOOST_SPIRIT_X3_DEBUG)
19#include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
20#endif
21
22#include <type_traits>
23
24namespace boost { namespace spirit { namespace x3
25{
26 template <typename ID>
27 struct identity;
28
29 template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
30 struct rule;
31
32 struct parse_pass_context_tag;
33
34 namespace detail
35 {
36 template <typename ID>
37 struct rule_id {};
38
39 // we use this so we can detect if the default parse_rule
40 // is the being called.
41 struct default_parse_rule_result
42 {
43 default_parse_rule_result(bool r)
44 : r(r) {}
45 operator bool() const { return r; }
46 bool r;
47 };
48 }
49
50 // default parse_rule implementation
51 template <typename ID, typename Iterator
52 , typename Context, typename ActualAttribute>
53 inline detail::default_parse_rule_result
54 parse_rule(
55 detail::rule_id<ID>
56 , Iterator& first, Iterator const& last
57 , Context const& context, ActualAttribute& attr);
58}}}
59
60namespace boost { namespace spirit { namespace x3 { namespace detail
61{
62#if defined(BOOST_SPIRIT_X3_DEBUG)
63 template <typename Iterator, typename Attribute>
64 struct context_debug
65 {
66 context_debug(
67 char const* rule_name
68 , Iterator const& first, Iterator const& last
69 , Attribute const& attr
70 , bool const& ok_parse //was parse successful?
71 )
72 : ok_parse(ok_parse), rule_name(rule_name)
73 , first(first), last(last)
74 , attr(attr)
75 , f(detail::get_simple_trace())
76 {
77 f(first, last, attr, pre_parse, rule_name);
78 }
79
80 ~context_debug()
81 {
82 auto status = ok_parse ? successful_parse : failed_parse ;
83 f(first, last, attr, status, rule_name);
84 }
85
86 bool const& ok_parse;
87 char const* rule_name;
88 Iterator const& first;
89 Iterator const& last;
90 Attribute const& attr;
91 detail::simple_trace_type& f;
92 };
93#endif
94
95 template <typename ID, typename Iterator, typename Context, typename Enable = void>
96 struct has_on_error : mpl::false_ {};
97
98 template <typename ID, typename Iterator, typename Context>
99 struct has_on_error<ID, Iterator, Context,
100 decltype(void(
101 std::declval<ID>().on_error(
102 std::declval<Iterator&>()
103 , std::declval<Iterator>()
104 , std::declval<expectation_failure<Iterator>>()
105 , std::declval<Context>()
106 )
107 ))
108 >
109 : mpl::true_
110 {};
111
112 template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
113 struct has_on_success : mpl::false_ {};
114
115 template <typename ID, typename Iterator, typename Attribute, typename Context>
116 struct has_on_success<ID, Iterator, Context, Attribute,
117 decltype(void(
118 std::declval<ID>().on_success(
119 std::declval<Iterator&>()
120 , std::declval<Iterator&>()
121 , std::declval<Attribute&>()
122 , std::declval<Context>()
123 )
124 ))
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, bool skip_definition_injection = false>
157 struct rule_parser
158 {
159 template <typename Iterator, typename Context, typename ActualAttribute>
160 static bool call_on_success(
161 Iterator& /* before */, Iterator& /* after */
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& before, Iterator& after
171 , Context const& context, ActualAttribute& attr
172 , mpl::true_ /* Has on_success handler */)
173 {
174 x3::skip_over(before, after, context);
175 bool pass = true;
176 ID().on_success(
177 before
178 , after
179 , attr
180 , make_context<parse_pass_context_tag>(pass, context)
181 );
182 return pass;
183 }
184
185 template <typename RHS, typename Iterator, typename Context
186 , typename RContext, typename ActualAttribute>
187 static bool parse_rhs_main(
188 RHS const& rhs
189 , Iterator& first, Iterator const& last
190 , Context const& context, RContext& rcontext, ActualAttribute& attr
191 , mpl::false_)
192 {
193 // see if the user has a BOOST_SPIRIT_DEFINE for this rule
194 typedef
195 decltype(parse_rule(
196 detail::rule_id<ID>{}, first, last
197 , make_unique_context<ID>(rhs, context), std::declval<Attribute&>()))
198 parse_rule_result;
199
200 // If there is no BOOST_SPIRIT_DEFINE for this rule,
201 // we'll make a context for this rule tagged by its ID
202 // so we can extract the rule later on in the default
203 // (generic) parse_rule function.
204 typedef
205 is_same<parse_rule_result, default_parse_rule_result>
206 is_default_parse_rule;
207
208 Iterator start = first;
209 bool r = rhs.parse(
210 first
211 , last
212 , make_rule_context<ID>(rhs, context, std::conditional_t<skip_definition_injection, mpl::false_, is_default_parse_rule>())
213 , rcontext
214 , attr
215 );
216
217 if (r)
218 {
219 r = call_on_success(start, first, context, attr
220 , has_on_success<ID, Iterator, Context, ActualAttribute>());
221 }
222
223 return r;
224 }
225
226 template <typename RHS, typename Iterator, typename Context
227 , typename RContext, typename ActualAttribute>
228 static bool parse_rhs_main(
229 RHS const& rhs
230 , Iterator& first, Iterator const& last
231 , Context const& context, RContext& rcontext, ActualAttribute& attr
232 , mpl::true_ /* on_error is found */)
233 {
234 for (;;)
235 {
236 try
237 {
238 return parse_rhs_main(
239 rhs, first, last, context, rcontext, attr, mpl::false_());
240 }
241 catch (expectation_failure<Iterator> const& x)
242 {
243 switch (ID().on_error(first, last, x, context))
244 {
245 case error_handler_result::fail:
246 return false;
247 case error_handler_result::retry:
248 continue;
249 case error_handler_result::accept:
250 return true;
251 case error_handler_result::rethrow:
252 throw;
253 }
254 }
255 }
256 }
257
258 template <typename RHS, typename Iterator
259 , typename Context, typename RContext, typename ActualAttribute>
260 static bool parse_rhs_main(
261 RHS const& rhs
262 , Iterator& first, Iterator const& last
263 , Context const& context, RContext& rcontext, ActualAttribute& attr)
264 {
265 return parse_rhs_main(
266 rhs, first, last, context, rcontext, attr
267 , has_on_error<ID, Iterator, Context>()
268 );
269 }
270
271 template <typename RHS, typename Iterator
272 , typename Context, typename RContext, typename ActualAttribute>
273 static bool parse_rhs(
274 RHS const& rhs
275 , Iterator& first, Iterator const& last
276 , Context const& context, RContext& rcontext, ActualAttribute& attr
277 , mpl::false_)
278 {
279 return parse_rhs_main(rhs, first, last, context, rcontext, attr);
280 }
281
282 template <typename RHS, typename Iterator
283 , typename Context, typename RContext, typename ActualAttribute>
284 static bool parse_rhs(
285 RHS const& rhs
286 , Iterator& first, Iterator const& last
287 , Context const& context, RContext& rcontext, ActualAttribute& /* attr */
288 , mpl::true_)
289 {
290 return parse_rhs_main(rhs, first, last, context, rcontext, unused);
291 }
292
293 template <typename RHS, typename Iterator, typename Context
294 , typename ActualAttribute, typename ExplicitAttrPropagation>
295 static bool call_rule_definition(
296 RHS const& rhs
297 , char const* rule_name
298 , Iterator& first, Iterator const& last
299 , Context const& context, ActualAttribute& attr
300 , ExplicitAttrPropagation)
301 {
302 boost::ignore_unused(rule_name);
303
304 // do down-stream transformation, provides attribute for
305 // rhs parser
306 typedef traits::transform_attribute<
307 ActualAttribute, Attribute, parser_id>
308 transform;
309
310 typedef typename transform::type transform_attr;
311 transform_attr attr_ = transform::pre(attr);
312
313 bool ok_parse
314 //Creates a place to hold the result of parse_rhs
315 //called inside the following scope.
316 ;
317 {
318 // Create a scope to cause the dbg variable below (within
319 // the #if...#endif) to call it's DTOR before any
320 // modifications are made to the attribute, attr_ passed
321 // to parse_rhs (such as might be done in
322 // transform::post when, for example,
323 // ActualAttribute is a recursive variant).
324#if defined(BOOST_SPIRIT_X3_DEBUG)
325 context_debug<Iterator, transform_attr>
326 dbg(rule_name, first, last, attr_, ok_parse);
327#endif
328 ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
329 , mpl::bool_
330 < ( RHS::has_action
331 && !ExplicitAttrPropagation::value
332 )
333 >()
334 );
335 }
336 if (ok_parse)
337 {
338 // do up-stream transformation, this integrates the results
339 // back into the original attribute value, if appropriate
340 transform::post(attr, std::forward<transform_attr>(attr_));
341 }
342 return ok_parse;
343 }
344 };
345}}}}
346
347#endif
348

source code of boost/libs/spirit/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp