Chris@102
|
1 /*=============================================================================
|
Chris@102
|
2 Copyright (c) 2001-2014 Joel de Guzman
|
Chris@102
|
3
|
Chris@102
|
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@102
|
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
6 ==============================================================================*/
|
Chris@102
|
7 #if !defined(BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM)
|
Chris@102
|
8 #define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM
|
Chris@102
|
9
|
Chris@102
|
10 #if defined(_MSC_VER)
|
Chris@102
|
11 #pragma once
|
Chris@102
|
12 #endif
|
Chris@102
|
13
|
Chris@102
|
14 #include <boost/spirit/home/x3/core/parser.hpp>
|
Chris@102
|
15 #include <boost/spirit/home/x3/support/traits/make_attribute.hpp>
|
Chris@102
|
16 #include <boost/spirit/home/x3/support/utility/sfinae.hpp>
|
Chris@102
|
17 #include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
|
Chris@102
|
18 #include <boost/utility/addressof.hpp>
|
Chris@102
|
19
|
Chris@102
|
20 #if defined(BOOST_SPIRIT_X3_DEBUG)
|
Chris@102
|
21 #include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
|
Chris@102
|
22 #endif
|
Chris@102
|
23
|
Chris@102
|
24 namespace boost { namespace spirit { namespace x3
|
Chris@102
|
25 {
|
Chris@102
|
26 template <typename ID>
|
Chris@102
|
27 struct identity;
|
Chris@102
|
28
|
Chris@102
|
29 template <typename ID, typename Attribute = unused_type>
|
Chris@102
|
30 struct rule;
|
Chris@102
|
31
|
Chris@102
|
32 struct parse_pass_context_tag;
|
Chris@102
|
33
|
Chris@102
|
34 namespace detail
|
Chris@102
|
35 {
|
Chris@102
|
36 // we use this so we can detect if the default parse_rule
|
Chris@102
|
37 // is the being called.
|
Chris@102
|
38 struct default_parse_rule_result
|
Chris@102
|
39 {
|
Chris@102
|
40 default_parse_rule_result(bool r)
|
Chris@102
|
41 : r(r) {}
|
Chris@102
|
42 operator bool() const { return r; }
|
Chris@102
|
43 bool r;
|
Chris@102
|
44 };
|
Chris@102
|
45 }
|
Chris@102
|
46
|
Chris@102
|
47 // default parse_rule implementation
|
Chris@102
|
48 template <typename ID, typename Attribute, typename Iterator
|
Chris@102
|
49 , typename Context, typename ActualAttribute>
|
Chris@102
|
50 inline detail::default_parse_rule_result
|
Chris@102
|
51 parse_rule(
|
Chris@102
|
52 rule<ID, Attribute> rule_
|
Chris@102
|
53 , Iterator& first, Iterator const& last
|
Chris@102
|
54 , Context const& context, ActualAttribute& attr);
|
Chris@102
|
55 }}}
|
Chris@102
|
56
|
Chris@102
|
57 namespace boost { namespace spirit { namespace x3 { namespace detail
|
Chris@102
|
58 {
|
Chris@102
|
59 #if defined(BOOST_SPIRIT_X3_DEBUG)
|
Chris@102
|
60 template <typename Iterator, typename Attribute>
|
Chris@102
|
61 struct context_debug
|
Chris@102
|
62 {
|
Chris@102
|
63 context_debug(
|
Chris@102
|
64 char const* rule_name
|
Chris@102
|
65 , Iterator const& first, Iterator const& last
|
Chris@102
|
66 , Attribute const& attr
|
Chris@102
|
67 , bool const& ok_parse //was parse successful?
|
Chris@102
|
68 )
|
Chris@102
|
69 : ok_parse(ok_parse), rule_name(rule_name)
|
Chris@102
|
70 , first(first), last(last)
|
Chris@102
|
71 , attr(attr)
|
Chris@102
|
72 , f(detail::get_simple_trace())
|
Chris@102
|
73 {
|
Chris@102
|
74 f(first, last, attr, pre_parse, rule_name);
|
Chris@102
|
75 }
|
Chris@102
|
76
|
Chris@102
|
77 ~context_debug()
|
Chris@102
|
78 {
|
Chris@102
|
79 auto status = ok_parse ? successful_parse : failed_parse ;
|
Chris@102
|
80 f(first, last, attr, status, rule_name);
|
Chris@102
|
81 }
|
Chris@102
|
82
|
Chris@102
|
83 bool const& ok_parse;
|
Chris@102
|
84 char const* rule_name;
|
Chris@102
|
85 Iterator const& first;
|
Chris@102
|
86 Iterator const& last;
|
Chris@102
|
87 Attribute const& attr;
|
Chris@102
|
88 detail::simple_trace_type& f;
|
Chris@102
|
89 };
|
Chris@102
|
90 #endif
|
Chris@102
|
91
|
Chris@102
|
92 template <typename ID, typename Iterator, typename Context, typename Enable = void>
|
Chris@102
|
93 struct has_on_error : mpl::false_ {};
|
Chris@102
|
94
|
Chris@102
|
95 template <typename ID, typename Iterator, typename Context>
|
Chris@102
|
96 struct has_on_error<ID, Iterator, Context,
|
Chris@102
|
97 typename disable_if_substitution_failure<
|
Chris@102
|
98 decltype(
|
Chris@102
|
99 std::declval<ID>().on_error(
|
Chris@102
|
100 std::declval<Iterator&>()
|
Chris@102
|
101 , std::declval<Iterator>()
|
Chris@102
|
102 , std::declval<expectation_failure<Iterator>>()
|
Chris@102
|
103 , std::declval<Context>()
|
Chris@102
|
104 )
|
Chris@102
|
105 )>::type
|
Chris@102
|
106 >
|
Chris@102
|
107 : mpl::true_
|
Chris@102
|
108 {};
|
Chris@102
|
109
|
Chris@102
|
110 template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
|
Chris@102
|
111 struct has_on_success : mpl::false_ {};
|
Chris@102
|
112
|
Chris@102
|
113 template <typename ID, typename Iterator, typename Attribute, typename Context>
|
Chris@102
|
114 struct has_on_success<ID, Iterator, Context, Attribute,
|
Chris@102
|
115 typename disable_if_substitution_failure<
|
Chris@102
|
116 decltype(
|
Chris@102
|
117 std::declval<ID>().on_success(
|
Chris@102
|
118 std::declval<Iterator&>()
|
Chris@102
|
119 , std::declval<Iterator>()
|
Chris@102
|
120 , std::declval<Attribute&>()
|
Chris@102
|
121 , std::declval<Context>()
|
Chris@102
|
122 )
|
Chris@102
|
123 )>::type
|
Chris@102
|
124 >
|
Chris@102
|
125 : mpl::true_
|
Chris@102
|
126 {};
|
Chris@102
|
127
|
Chris@102
|
128 template <typename ID>
|
Chris@102
|
129 struct make_id
|
Chris@102
|
130 {
|
Chris@102
|
131 typedef identity<ID> type;
|
Chris@102
|
132 };
|
Chris@102
|
133
|
Chris@102
|
134 template <typename ID>
|
Chris@102
|
135 struct make_id<identity<ID>>
|
Chris@102
|
136 {
|
Chris@102
|
137 typedef identity<ID> type;
|
Chris@102
|
138 };
|
Chris@102
|
139
|
Chris@102
|
140 template <typename ID, typename RHS, typename Context>
|
Chris@102
|
141 Context const&
|
Chris@102
|
142 make_rule_context(RHS const& rhs, Context const& context
|
Chris@102
|
143 , mpl::false_ /* is_default_parse_rule */)
|
Chris@102
|
144 {
|
Chris@102
|
145 return context;
|
Chris@102
|
146 }
|
Chris@102
|
147
|
Chris@102
|
148 template <typename ID, typename RHS, typename Context>
|
Chris@102
|
149 auto make_rule_context(RHS const& rhs, Context const& context
|
Chris@102
|
150 , mpl::true_ /* is_default_parse_rule */ )
|
Chris@102
|
151 {
|
Chris@102
|
152 return make_unique_context<ID>(rhs, context);
|
Chris@102
|
153 }
|
Chris@102
|
154
|
Chris@102
|
155 template <typename Attribute, typename ID>
|
Chris@102
|
156 struct rule_parser
|
Chris@102
|
157 {
|
Chris@102
|
158 template <typename Iterator, typename Context, typename ActualAttribute>
|
Chris@102
|
159 static bool call_on_success(
|
Chris@102
|
160 Iterator& first, Iterator const& last
|
Chris@102
|
161 , Context const& context, ActualAttribute& attr
|
Chris@102
|
162 , mpl::false_ /* No on_success handler */ )
|
Chris@102
|
163 {
|
Chris@102
|
164 return true;
|
Chris@102
|
165 }
|
Chris@102
|
166
|
Chris@102
|
167 template <typename Iterator, typename Context, typename ActualAttribute>
|
Chris@102
|
168 static bool call_on_success(
|
Chris@102
|
169 Iterator& first, Iterator const& last
|
Chris@102
|
170 , Context const& context, ActualAttribute& attr
|
Chris@102
|
171 , mpl::true_ /* Has on_success handler */)
|
Chris@102
|
172 {
|
Chris@102
|
173 bool pass = true;
|
Chris@102
|
174 ID().on_success(
|
Chris@102
|
175 first
|
Chris@102
|
176 , last
|
Chris@102
|
177 , attr
|
Chris@102
|
178 , make_context<parse_pass_context_tag>(pass, context)
|
Chris@102
|
179 );
|
Chris@102
|
180 return pass;
|
Chris@102
|
181 }
|
Chris@102
|
182
|
Chris@102
|
183 template <typename RHS, typename Iterator, typename Context
|
Chris@102
|
184 , typename RContext, typename ActualAttribute>
|
Chris@102
|
185 static bool parse_rhs_main(
|
Chris@102
|
186 RHS const& rhs
|
Chris@102
|
187 , Iterator& first, Iterator const& last
|
Chris@102
|
188 , Context const& context, RContext& rcontext, ActualAttribute& attr
|
Chris@102
|
189 , mpl::false_)
|
Chris@102
|
190 {
|
Chris@102
|
191 // see if the user has a BOOST_SPIRIT_DEFINE for this rule
|
Chris@102
|
192 typedef
|
Chris@102
|
193 decltype(parse_rule(
|
Chris@102
|
194 rule<ID, Attribute>(), first, last
|
Chris@102
|
195 , make_unique_context<ID>(rhs, context), attr))
|
Chris@102
|
196 parse_rule_result;
|
Chris@102
|
197
|
Chris@102
|
198 // If there is no BOOST_SPIRIT_DEFINE for this rule,
|
Chris@102
|
199 // we'll make a context for this rule tagged by its ID
|
Chris@102
|
200 // so we can extract the rule later on in the default
|
Chris@102
|
201 // (generic) parse_rule function.
|
Chris@102
|
202 typedef
|
Chris@102
|
203 is_same<parse_rule_result, default_parse_rule_result>
|
Chris@102
|
204 is_default_parse_rule;
|
Chris@102
|
205
|
Chris@102
|
206 Iterator i = first;
|
Chris@102
|
207 bool r = rhs.parse(
|
Chris@102
|
208 i
|
Chris@102
|
209 , last
|
Chris@102
|
210 , make_rule_context<ID>(rhs, context, is_default_parse_rule())
|
Chris@102
|
211 , rcontext
|
Chris@102
|
212 , attr
|
Chris@102
|
213 );
|
Chris@102
|
214
|
Chris@102
|
215 if (r)
|
Chris@102
|
216 {
|
Chris@102
|
217 auto first_ = first;
|
Chris@102
|
218 x3::skip_over(first_, last, context);
|
Chris@102
|
219 r = call_on_success(first_, i, context, attr
|
Chris@102
|
220 , has_on_success<ID, Iterator, Context, ActualAttribute>());
|
Chris@102
|
221 }
|
Chris@102
|
222
|
Chris@102
|
223 if (r)
|
Chris@102
|
224 first = i;
|
Chris@102
|
225 return r;
|
Chris@102
|
226 }
|
Chris@102
|
227
|
Chris@102
|
228 template <typename RHS, typename Iterator, typename Context
|
Chris@102
|
229 , typename RContext, typename ActualAttribute>
|
Chris@102
|
230 static bool parse_rhs_main(
|
Chris@102
|
231 RHS const& rhs
|
Chris@102
|
232 , Iterator& first, Iterator const& last
|
Chris@102
|
233 , Context const& context, RContext& rcontext, ActualAttribute& attr
|
Chris@102
|
234 , mpl::true_ /* on_error is found */)
|
Chris@102
|
235 {
|
Chris@102
|
236 for (;;)
|
Chris@102
|
237 {
|
Chris@102
|
238 try
|
Chris@102
|
239 {
|
Chris@102
|
240 return parse_rhs_main(
|
Chris@102
|
241 rhs, first, last, context, rcontext, attr, mpl::false_());
|
Chris@102
|
242 }
|
Chris@102
|
243 catch (expectation_failure<Iterator> const& x)
|
Chris@102
|
244 {
|
Chris@102
|
245 switch (ID().on_error(first, last, x, context))
|
Chris@102
|
246 {
|
Chris@102
|
247 case error_handler_result::fail:
|
Chris@102
|
248 return false;
|
Chris@102
|
249 case error_handler_result::retry:
|
Chris@102
|
250 continue;
|
Chris@102
|
251 case error_handler_result::accept:
|
Chris@102
|
252 return true;
|
Chris@102
|
253 case error_handler_result::rethrow:
|
Chris@102
|
254 throw;
|
Chris@102
|
255 }
|
Chris@102
|
256 }
|
Chris@102
|
257 }
|
Chris@102
|
258 }
|
Chris@102
|
259
|
Chris@102
|
260 template <typename RHS, typename Iterator
|
Chris@102
|
261 , typename Context, typename RContext, typename ActualAttribute>
|
Chris@102
|
262 static bool parse_rhs_main(
|
Chris@102
|
263 RHS const& rhs
|
Chris@102
|
264 , Iterator& first, Iterator const& last
|
Chris@102
|
265 , Context const& context, RContext& rcontext, ActualAttribute& attr)
|
Chris@102
|
266 {
|
Chris@102
|
267 return parse_rhs_main(
|
Chris@102
|
268 rhs, first, last, context, rcontext, attr
|
Chris@102
|
269 , has_on_error<ID, Iterator, Context>()
|
Chris@102
|
270 );
|
Chris@102
|
271 }
|
Chris@102
|
272
|
Chris@102
|
273 template <typename RHS, typename Iterator
|
Chris@102
|
274 , typename Context, typename RContext, typename ActualAttribute>
|
Chris@102
|
275 static bool parse_rhs(
|
Chris@102
|
276 RHS const& rhs
|
Chris@102
|
277 , Iterator& first, Iterator const& last
|
Chris@102
|
278 , Context const& context, RContext& rcontext, ActualAttribute& attr
|
Chris@102
|
279 , mpl::false_)
|
Chris@102
|
280 {
|
Chris@102
|
281 return parse_rhs_main(rhs, first, last, context, rcontext, attr);
|
Chris@102
|
282 }
|
Chris@102
|
283
|
Chris@102
|
284 template <typename RHS, typename Iterator
|
Chris@102
|
285 , typename Context, typename RContext, typename ActualAttribute>
|
Chris@102
|
286 static bool parse_rhs(
|
Chris@102
|
287 RHS const& rhs
|
Chris@102
|
288 , Iterator& first, Iterator const& last
|
Chris@102
|
289 , Context const& context, RContext& rcontext, ActualAttribute& attr
|
Chris@102
|
290 , mpl::true_)
|
Chris@102
|
291 {
|
Chris@102
|
292 return parse_rhs_main(rhs, first, last, context, rcontext, unused);
|
Chris@102
|
293 }
|
Chris@102
|
294
|
Chris@102
|
295 template <typename RHS, typename Iterator, typename Context
|
Chris@102
|
296 , typename ActualAttribute, typename ExplicitAttrPropagation>
|
Chris@102
|
297 static bool call_rule_definition(
|
Chris@102
|
298 RHS const& rhs
|
Chris@102
|
299 , char const* rule_name
|
Chris@102
|
300 , Iterator& first, Iterator const& last
|
Chris@102
|
301 , Context const& context, ActualAttribute& attr
|
Chris@102
|
302 , ExplicitAttrPropagation)
|
Chris@102
|
303 {
|
Chris@102
|
304 typedef traits::make_attribute<Attribute, ActualAttribute> make_attribute;
|
Chris@102
|
305
|
Chris@102
|
306 // do down-stream transformation, provides attribute for
|
Chris@102
|
307 // rhs parser
|
Chris@102
|
308 typedef traits::transform_attribute<
|
Chris@102
|
309 typename make_attribute::type, Attribute, parser_id>
|
Chris@102
|
310 transform;
|
Chris@102
|
311
|
Chris@102
|
312 typedef typename make_attribute::value_type value_type;
|
Chris@102
|
313 typedef typename transform::type transform_attr;
|
Chris@102
|
314 value_type made_attr = make_attribute::call(attr);
|
Chris@102
|
315 transform_attr attr_ = transform::pre(made_attr);
|
Chris@102
|
316
|
Chris@102
|
317 bool ok_parse
|
Chris@102
|
318 //Creates a place to hold the result of parse_rhs
|
Chris@102
|
319 //called inside the following scope.
|
Chris@102
|
320 ;
|
Chris@102
|
321 {
|
Chris@102
|
322 //Create a scope to cause the dbg variable below (within
|
Chris@102
|
323 //the #if...#endif) to call it's DTOR before any
|
Chris@102
|
324 //modifications are made to the attribute, attr_ passed
|
Chris@102
|
325 //to parse_rhs (such as might be done in
|
Chris@102
|
326 //traits::post_transform when, for example,
|
Chris@102
|
327 //ActualAttribute is a recursive variant).
|
Chris@102
|
328 #if defined(BOOST_SPIRIT_X3_DEBUG)
|
Chris@102
|
329 context_debug<Iterator, typename make_attribute::value_type>
|
Chris@102
|
330 dbg(rule_name, first, last, attr_, ok_parse);
|
Chris@102
|
331 #endif
|
Chris@102
|
332 ok_parse=parse_rhs(rhs, first, last, context, attr_, attr_
|
Chris@102
|
333 , mpl::bool_
|
Chris@102
|
334 < ( RHS::has_action
|
Chris@102
|
335 && !ExplicitAttrPropagation::value
|
Chris@102
|
336 )
|
Chris@102
|
337 >()
|
Chris@102
|
338 );
|
Chris@102
|
339 }
|
Chris@102
|
340 if(ok_parse)
|
Chris@102
|
341 {
|
Chris@102
|
342 // do up-stream transformation, this integrates the results
|
Chris@102
|
343 // back into the original attribute value, if appropriate
|
Chris@102
|
344 traits::post_transform(attr, attr_);
|
Chris@102
|
345 }
|
Chris@102
|
346 return ok_parse;
|
Chris@102
|
347 }
|
Chris@102
|
348
|
Chris@102
|
349 // template <typename RuleDef, typename Iterator, typename Context
|
Chris@102
|
350 // , typename ActualAttribute, typename AttributeContext>
|
Chris@102
|
351 // static bool call_from_rule(
|
Chris@102
|
352 // RuleDef const& rule_def
|
Chris@102
|
353 // , char const* rule_name
|
Chris@102
|
354 // , Iterator& first, Iterator const& last
|
Chris@102
|
355 // , Context const& context, ActualAttribute& attr, AttributeContext& attr_ctx)
|
Chris@102
|
356 // {
|
Chris@102
|
357 // // This is called when a rule-body has already been established.
|
Chris@102
|
358 // // The rule body is already established by the rule_definition class,
|
Chris@102
|
359 // // we will not do it again. We'll simply call the RHS by calling
|
Chris@102
|
360 // // call_rule_definition.
|
Chris@102
|
361 //
|
Chris@102
|
362 // return call_rule_definition(
|
Chris@102
|
363 // rule_def.rhs, rule_name, first, last
|
Chris@102
|
364 // , context, attr, attr_ctx.attr_ptr
|
Chris@102
|
365 // , mpl::bool_<(RuleDef::explicit_attribute_propagation)>());
|
Chris@102
|
366 // }
|
Chris@102
|
367 //
|
Chris@102
|
368 // template <typename RuleDef, typename Iterator, typename Context
|
Chris@102
|
369 // , typename ActualAttribute>
|
Chris@102
|
370 // static bool call_from_rule(
|
Chris@102
|
371 // RuleDef const& rule_def
|
Chris@102
|
372 // , char const* rule_name
|
Chris@102
|
373 // , Iterator& first, Iterator const& last
|
Chris@102
|
374 // , Context const& context, ActualAttribute& attr, unused_type)
|
Chris@102
|
375 // {
|
Chris@102
|
376 // // This is called when a rule-body has *not yet* been established.
|
Chris@102
|
377 // // The rule body is established by the rule_definition class, so
|
Chris@102
|
378 // // we call it to parse and establish the rule-body.
|
Chris@102
|
379 //
|
Chris@102
|
380 // return rule_def.parse(first, last, context, unused, attr); // $$$ fix unused param $$$
|
Chris@102
|
381 // }
|
Chris@102
|
382 };
|
Chris@102
|
383 }}}}
|
Chris@102
|
384
|
Chris@102
|
385 #endif
|