]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 | 10 | #include <boost/core/ignore_unused.hpp> |
7c673cae FG |
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> | |
7c673cae FG |
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 | ||
92f5a8d4 TL |
23 | #include <type_traits> |
24 | ||
7c673cae FG |
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& | |
b32b8144 | 143 | make_rule_context(RHS const& /* rhs */, Context const& context |
7c673cae FG |
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( | |
b32b8144 FG |
161 | Iterator& /* first */, Iterator const& /* last */ |
162 | , Context const& /* context */, ActualAttribute& /* attr */ | |
7c673cae FG |
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 | |
92f5a8d4 | 196 | , make_unique_context<ID>(rhs, context), std::declval<Attribute&>())) |
7c673cae FG |
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 | |
b32b8144 | 290 | , Context const& context, RContext& rcontext, ActualAttribute& /* attr */ |
7c673cae FG |
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 | { | |
b32b8144 FG |
305 | boost::ignore_unused(rule_name); |
306 | ||
7c673cae FG |
307 | // do down-stream transformation, provides attribute for |
308 | // rhs parser | |
309 | typedef traits::transform_attribute< | |
92f5a8d4 | 310 | ActualAttribute, Attribute, parser_id> |
7c673cae FG |
311 | transform; |
312 | ||
7c673cae | 313 | typedef typename transform::type transform_attr; |
92f5a8d4 | 314 | transform_attr attr_ = transform::pre(attr); |
7c673cae FG |
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 | |
92f5a8d4 | 325 | // transform::post when, for example, |
7c673cae FG |
326 | // ActualAttribute is a recursive variant). |
327 | #if defined(BOOST_SPIRIT_X3_DEBUG) | |
b32b8144 FG |
328 | context_debug<Iterator, transform_attr> |
329 | dbg(rule_name, first, last, attr_, ok_parse); | |
7c673cae FG |
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 | |
92f5a8d4 | 343 | transform::post(attr, std::forward<transform_attr>(attr_)); |
7c673cae FG |
344 | } |
345 | return ok_parse; | |
346 | } | |
347 | }; | |
348 | }}}} | |
349 | ||
350 | #endif |