]>
Commit | Line | Data |
---|---|---|
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/spirit/home/x3/auxiliary/guard.hpp> | |
11 | #include <boost/spirit/home/x3/core/parser.hpp> | |
12 | #include <boost/spirit/home/x3/core/skip_over.hpp> | |
13 | #include <boost/spirit/home/x3/directive/expect.hpp> | |
14 | #include <boost/spirit/home/x3/support/traits/make_attribute.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 | namespace boost { namespace spirit { namespace x3 | |
24 | { | |
25 | template <typename ID> | |
26 | struct identity; | |
27 | ||
28 | template <typename ID, typename Attribute = unused_type, bool force_attribute = false> | |
29 | struct rule; | |
30 | ||
31 | struct parse_pass_context_tag; | |
32 | ||
33 | namespace detail | |
34 | { | |
35 | // we use this so we can detect if the default parse_rule | |
36 | // is the being called. | |
37 | struct default_parse_rule_result | |
38 | { | |
39 | default_parse_rule_result(bool r) | |
40 | : r(r) {} | |
41 | operator bool() const { return r; } | |
42 | bool r; | |
43 | }; | |
44 | } | |
45 | ||
46 | // default parse_rule implementation | |
47 | template <typename ID, typename Attribute, typename Iterator | |
48 | , typename Context, typename ActualAttribute> | |
49 | inline detail::default_parse_rule_result | |
50 | parse_rule( | |
51 | rule<ID, Attribute> rule_ | |
52 | , Iterator& first, Iterator const& last | |
53 | , Context const& context, ActualAttribute& attr); | |
54 | }}} | |
55 | ||
56 | namespace boost { namespace spirit { namespace x3 { namespace detail | |
57 | { | |
58 | #if defined(BOOST_SPIRIT_X3_DEBUG) | |
59 | template <typename Iterator, typename Attribute> | |
60 | struct context_debug | |
61 | { | |
62 | context_debug( | |
63 | char const* rule_name | |
64 | , Iterator const& first, Iterator const& last | |
65 | , Attribute const& attr | |
66 | , bool const& ok_parse //was parse successful? | |
67 | ) | |
68 | : ok_parse(ok_parse), rule_name(rule_name) | |
69 | , first(first), last(last) | |
70 | , attr(attr) | |
71 | , f(detail::get_simple_trace()) | |
72 | { | |
73 | f(first, last, attr, pre_parse, rule_name); | |
74 | } | |
75 | ||
76 | ~context_debug() | |
77 | { | |
78 | auto status = ok_parse ? successful_parse : failed_parse ; | |
79 | f(first, last, attr, status, rule_name); | |
80 | } | |
81 | ||
82 | bool const& ok_parse; | |
83 | char const* rule_name; | |
84 | Iterator const& first; | |
85 | Iterator const& last; | |
86 | Attribute const& attr; | |
87 | detail::simple_trace_type& f; | |
88 | }; | |
89 | #endif | |
90 | ||
91 | template <typename ID, typename Iterator, typename Context, typename Enable = void> | |
92 | struct has_on_error : mpl::false_ {}; | |
93 | ||
94 | template <typename ID, typename Iterator, typename Context> | |
95 | struct has_on_error<ID, Iterator, Context, | |
96 | typename disable_if_substitution_failure< | |
97 | decltype( | |
98 | std::declval<ID>().on_error( | |
99 | std::declval<Iterator&>() | |
100 | , std::declval<Iterator>() | |
101 | , std::declval<expectation_failure<Iterator>>() | |
102 | , std::declval<Context>() | |
103 | ) | |
104 | )>::type | |
105 | > | |
106 | : mpl::true_ | |
107 | {}; | |
108 | ||
109 | template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void> | |
110 | struct has_on_success : mpl::false_ {}; | |
111 | ||
112 | template <typename ID, typename Iterator, typename Attribute, typename Context> | |
113 | struct has_on_success<ID, Iterator, Context, Attribute, | |
114 | typename disable_if_substitution_failure< | |
115 | decltype( | |
116 | std::declval<ID>().on_success( | |
117 | std::declval<Iterator&>() | |
118 | , std::declval<Iterator>() | |
119 | , std::declval<Attribute&>() | |
120 | , std::declval<Context>() | |
121 | ) | |
122 | )>::type | |
123 | > | |
124 | : mpl::true_ | |
125 | {}; | |
126 | ||
127 | template <typename ID> | |
128 | struct make_id | |
129 | { | |
130 | typedef identity<ID> type; | |
131 | }; | |
132 | ||
133 | template <typename ID> | |
134 | struct make_id<identity<ID>> | |
135 | { | |
136 | typedef identity<ID> type; | |
137 | }; | |
138 | ||
139 | template <typename ID, typename RHS, typename Context> | |
140 | Context const& | |
141 | make_rule_context(RHS const& rhs, Context const& context | |
142 | , mpl::false_ /* is_default_parse_rule */) | |
143 | { | |
144 | return context; | |
145 | } | |
146 | ||
147 | template <typename ID, typename RHS, typename Context> | |
148 | auto make_rule_context(RHS const& rhs, Context const& context | |
149 | , mpl::true_ /* is_default_parse_rule */ ) | |
150 | { | |
151 | return make_unique_context<ID>(rhs, context); | |
152 | } | |
153 | ||
154 | template <typename Attribute, typename ID> | |
155 | struct rule_parser | |
156 | { | |
157 | template <typename Iterator, typename Context, typename ActualAttribute> | |
158 | static bool call_on_success( | |
159 | Iterator& first, Iterator const& last | |
160 | , Context const& context, ActualAttribute& attr | |
161 | , mpl::false_ /* No on_success handler */ ) | |
162 | { | |
163 | return true; | |
164 | } | |
165 | ||
166 | template <typename Iterator, typename Context, typename ActualAttribute> | |
167 | static bool call_on_success( | |
168 | Iterator& first, Iterator const& last | |
169 | , Context const& context, ActualAttribute& attr | |
170 | , mpl::true_ /* Has on_success handler */) | |
171 | { | |
172 | bool pass = true; | |
173 | ID().on_success( | |
174 | first | |
175 | , last | |
176 | , attr | |
177 | , make_context<parse_pass_context_tag>(pass, context) | |
178 | ); | |
179 | return pass; | |
180 | } | |
181 | ||
182 | template <typename RHS, typename Iterator, typename Context | |
183 | , typename RContext, typename ActualAttribute> | |
184 | static bool parse_rhs_main( | |
185 | RHS const& rhs | |
186 | , Iterator& first, Iterator const& last | |
187 | , Context const& context, RContext& rcontext, ActualAttribute& attr | |
188 | , mpl::false_) | |
189 | { | |
190 | // see if the user has a BOOST_SPIRIT_DEFINE for this rule | |
191 | typedef | |
192 | decltype(parse_rule( | |
193 | rule<ID, Attribute>(), first, last | |
194 | , make_unique_context<ID>(rhs, context), attr)) | |
195 | parse_rule_result; | |
196 | ||
197 | // If there is no BOOST_SPIRIT_DEFINE for this rule, | |
198 | // we'll make a context for this rule tagged by its ID | |
199 | // so we can extract the rule later on in the default | |
200 | // (generic) parse_rule function. | |
201 | typedef | |
202 | is_same<parse_rule_result, default_parse_rule_result> | |
203 | is_default_parse_rule; | |
204 | ||
205 | Iterator i = first; | |
206 | bool r = rhs.parse( | |
207 | i | |
208 | , last | |
209 | , make_rule_context<ID>(rhs, context, is_default_parse_rule()) | |
210 | , rcontext | |
211 | , attr | |
212 | ); | |
213 | ||
214 | if (r) | |
215 | { | |
216 | auto first_ = first; | |
217 | x3::skip_over(first_, last, context); | |
218 | r = call_on_success(first_, i, context, attr | |
219 | , has_on_success<ID, Iterator, Context, ActualAttribute>()); | |
220 | } | |
221 | ||
222 | if (r) | |
223 | first = i; | |
224 | return r; | |
225 | } | |
226 | ||
227 | template <typename RHS, typename Iterator, typename Context | |
228 | , typename RContext, typename ActualAttribute> | |
229 | static bool parse_rhs_main( | |
230 | RHS const& rhs | |
231 | , Iterator& first, Iterator const& last | |
232 | , Context const& context, RContext& rcontext, ActualAttribute& attr | |
233 | , mpl::true_ /* on_error is found */) | |
234 | { | |
235 | for (;;) | |
236 | { | |
237 | try | |
238 | { | |
239 | return parse_rhs_main( | |
240 | rhs, first, last, context, rcontext, attr, mpl::false_()); | |
241 | } | |
242 | catch (expectation_failure<Iterator> const& x) | |
243 | { | |
244 | switch (ID().on_error(first, last, x, context)) | |
245 | { | |
246 | case error_handler_result::fail: | |
247 | return false; | |
248 | case error_handler_result::retry: | |
249 | continue; | |
250 | case error_handler_result::accept: | |
251 | return true; | |
252 | case error_handler_result::rethrow: | |
253 | throw; | |
254 | } | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | template <typename RHS, typename Iterator | |
260 | , typename Context, typename RContext, typename ActualAttribute> | |
261 | static bool parse_rhs_main( | |
262 | RHS const& rhs | |
263 | , Iterator& first, Iterator const& last | |
264 | , Context const& context, RContext& rcontext, ActualAttribute& attr) | |
265 | { | |
266 | return parse_rhs_main( | |
267 | rhs, first, last, context, rcontext, attr | |
268 | , has_on_error<ID, Iterator, Context>() | |
269 | ); | |
270 | } | |
271 | ||
272 | template <typename RHS, typename Iterator | |
273 | , typename Context, typename RContext, typename ActualAttribute> | |
274 | static bool parse_rhs( | |
275 | RHS const& rhs | |
276 | , Iterator& first, Iterator const& last | |
277 | , Context const& context, RContext& rcontext, ActualAttribute& attr | |
278 | , mpl::false_) | |
279 | { | |
280 | return parse_rhs_main(rhs, first, last, context, rcontext, attr); | |
281 | } | |
282 | ||
283 | template <typename RHS, typename Iterator | |
284 | , typename Context, typename RContext, typename ActualAttribute> | |
285 | static bool parse_rhs( | |
286 | RHS const& rhs | |
287 | , Iterator& first, Iterator const& last | |
288 | , Context const& context, RContext& rcontext, ActualAttribute& attr | |
289 | , mpl::true_) | |
290 | { | |
291 | return parse_rhs_main(rhs, first, last, context, rcontext, unused); | |
292 | } | |
293 | ||
294 | template <typename RHS, typename Iterator, typename Context | |
295 | , typename ActualAttribute, typename ExplicitAttrPropagation> | |
296 | static bool call_rule_definition( | |
297 | RHS const& rhs | |
298 | , char const* rule_name | |
299 | , Iterator& first, Iterator const& last | |
300 | , Context const& context, ActualAttribute& attr | |
301 | , ExplicitAttrPropagation) | |
302 | { | |
303 | typedef traits::make_attribute<Attribute, ActualAttribute> make_attribute; | |
304 | ||
305 | // do down-stream transformation, provides attribute for | |
306 | // rhs parser | |
307 | typedef traits::transform_attribute< | |
308 | typename make_attribute::type, Attribute, parser_id> | |
309 | transform; | |
310 | ||
311 | typedef typename make_attribute::value_type value_type; | |
312 | typedef typename transform::type transform_attr; | |
313 | value_type made_attr = make_attribute::call(attr); | |
314 | transform_attr attr_ = transform::pre(made_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 | // traits::post_transform when, for example, | |
326 | // ActualAttribute is a recursive variant). | |
327 | #if defined(BOOST_SPIRIT_X3_DEBUG) | |
328 | typedef typename make_attribute::type dbg_attribute_type; | |
329 | context_debug<Iterator, dbg_attribute_type> | |
330 | dbg(rule_name, first, last, dbg_attribute_type(attr_), ok_parse); | |
331 | #endif | |
332 | ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_ | |
333 | , mpl::bool_ | |
334 | < ( RHS::has_action | |
335 | && !ExplicitAttrPropagation::value | |
336 | ) | |
337 | >() | |
338 | ); | |
339 | } | |
340 | if (ok_parse) | |
341 | { | |
342 | // do up-stream transformation, this integrates the results | |
343 | // back into the original attribute value, if appropriate | |
344 | traits::post_transform(attr, std::forward<transform_attr>(attr_)); | |
345 | } | |
346 | return ok_parse; | |
347 | } | |
348 | }; | |
349 | }}}} | |
350 | ||
351 | #endif |