]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file matches.hpp | |
3 | /// Contains definition of matches\<\> metafunction for determining if | |
4 | /// a given expression matches a given pattern. | |
5 | // | |
6 | // Copyright 2008 Eric Niebler. Distributed under the Boost | |
7 | // Software License, Version 1.0. (See accompanying file | |
8 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | ||
10 | #ifndef BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006 | |
11 | #define BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006 | |
12 | ||
13 | #include <boost/config.hpp> | |
14 | #include <boost/detail/workaround.hpp> | |
15 | #include <boost/preprocessor/cat.hpp> | |
16 | #include <boost/preprocessor/arithmetic/dec.hpp> | |
17 | #include <boost/preprocessor/arithmetic/sub.hpp> | |
18 | #include <boost/preprocessor/iteration/iterate.hpp> | |
19 | #include <boost/preprocessor/facilities/intercept.hpp> | |
20 | #include <boost/preprocessor/punctuation/comma_if.hpp> | |
21 | #include <boost/preprocessor/repetition/enum.hpp> | |
22 | #include <boost/preprocessor/repetition/enum_params.hpp> | |
23 | #include <boost/preprocessor/repetition/enum_shifted.hpp> | |
24 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
25 | #include <boost/preprocessor/repetition/enum_shifted_params.hpp> | |
26 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
27 | #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> | |
28 | #include <boost/preprocessor/repetition/repeat.hpp> | |
29 | #include <boost/config.hpp> | |
30 | #include <boost/mpl/logical.hpp> | |
31 | #include <boost/mpl/eval_if.hpp> | |
32 | #include <boost/proto/detail/template_arity.hpp> | |
33 | #include <boost/utility/enable_if.hpp> | |
34 | #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) | |
35 | #include <boost/type_traits/is_array.hpp> | |
36 | #endif | |
37 | #include <boost/type_traits/is_const.hpp> | |
38 | #include <boost/type_traits/is_convertible.hpp> | |
39 | #include <boost/type_traits/is_reference.hpp> | |
40 | #include <boost/type_traits/is_pointer.hpp> | |
41 | #include <boost/proto/proto_fwd.hpp> | |
42 | #include <boost/proto/traits.hpp> | |
43 | #include <boost/proto/transform/when.hpp> | |
44 | #include <boost/proto/transform/impl.hpp> | |
45 | ||
46 | #if defined(_MSC_VER) | |
47 | # pragma warning(push) | |
48 | # pragma warning(disable:4305) // 'specialization' : truncation from 'const int' to 'bool' | |
49 | #endif | |
50 | ||
51 | #define BOOST_PROTO_LOGICAL_typename_G BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, typename G) | |
52 | #define BOOST_PROTO_LOGICAL_G BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, G) | |
53 | ||
54 | namespace boost { namespace proto | |
55 | { | |
56 | ||
57 | namespace detail | |
58 | { | |
59 | template<typename Expr, typename BasicExpr, typename Grammar> | |
60 | struct matches_; | |
61 | ||
62 | template<bool B, typename Pred> | |
63 | struct and_2; | |
64 | ||
65 | template<typename And, typename Expr, typename State, typename Data> | |
66 | struct _and_impl; | |
67 | ||
68 | template<typename T, typename U> | |
69 | struct array_matches | |
70 | : mpl::false_ | |
71 | {}; | |
72 | ||
73 | template<typename T, std::size_t M> | |
74 | struct array_matches<T[M], T *> | |
75 | : mpl::true_ | |
76 | {}; | |
77 | ||
78 | template<typename T, std::size_t M> | |
79 | struct array_matches<T[M], T const *> | |
80 | : mpl::true_ | |
81 | {}; | |
82 | ||
83 | template<typename T, std::size_t M> | |
84 | struct array_matches<T[M], T[proto::N]> | |
85 | : mpl::true_ | |
86 | {}; | |
87 | ||
88 | template<typename T, typename U | |
89 | BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity<U>::value) | |
90 | > | |
91 | struct lambda_matches | |
92 | : mpl::false_ | |
93 | {}; | |
94 | ||
95 | template<typename T> | |
96 | struct lambda_matches<T, proto::_ BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)> | |
97 | : mpl::true_ | |
98 | {}; | |
99 | ||
100 | template<typename T> | |
101 | struct lambda_matches<T, T BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)> | |
102 | : mpl::true_ | |
103 | {}; | |
104 | ||
105 | template<typename T, std::size_t M, typename U> | |
106 | struct lambda_matches<T[M], U BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)> | |
107 | : array_matches<T[M], U> | |
108 | {}; | |
109 | ||
110 | template<typename T, std::size_t M> | |
111 | struct lambda_matches<T[M], _ BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)> | |
112 | : mpl::true_ | |
113 | {}; | |
114 | ||
115 | template<typename T, std::size_t M> | |
116 | struct lambda_matches<T[M], T[M] BOOST_PROTO_TEMPLATE_ARITY_PARAM(-1)> | |
117 | : mpl::true_ | |
118 | {}; | |
119 | ||
120 | template<template<typename> class T, typename Expr0, typename Grammar0> | |
121 | struct lambda_matches<T<Expr0>, T<Grammar0> BOOST_PROTO_TEMPLATE_ARITY_PARAM(1) > | |
122 | : lambda_matches<Expr0, Grammar0> | |
123 | {}; | |
124 | ||
125 | // vararg_matches_impl | |
126 | template<typename Args1, typename Back, long From, long To> | |
127 | struct vararg_matches_impl; | |
128 | ||
129 | // vararg_matches | |
130 | template<typename Expr, typename Args1, typename Args2, typename Back, bool Can, bool Zero, typename Void = void> | |
131 | struct vararg_matches | |
132 | : mpl::false_ | |
133 | {}; | |
134 | ||
135 | template<typename Expr, typename Args1, typename Args2, typename Back> | |
136 | struct vararg_matches<Expr, Args1, Args2, Back, true, true, typename Back::proto_is_vararg_> | |
137 | : matches_< | |
138 | Expr | |
139 | , proto::basic_expr<ignore, Args1, Args1::arity> | |
140 | , proto::basic_expr<ignore, Args2, Args1::arity> | |
141 | > | |
142 | {}; | |
143 | ||
144 | template<typename Expr, typename Args1, typename Args2, typename Back> | |
145 | struct vararg_matches<Expr, Args1, Args2, Back, true, false, typename Back::proto_is_vararg_> | |
146 | : and_2< | |
147 | matches_< | |
148 | Expr | |
149 | , proto::basic_expr<ignore, Args1, Args2::arity> | |
150 | , proto::basic_expr<ignore, Args2, Args2::arity> | |
151 | >::value | |
152 | , vararg_matches_impl<Args1, typename Back::proto_grammar, Args2::arity + 1, Args1::arity> | |
153 | > | |
154 | {}; | |
155 | ||
156 | // How terminal_matches<> handles references and cv-qualifiers. | |
157 | // The cv and ref matter *only* if the grammar has a top-level ref. | |
158 | // | |
159 | // Expr | Grammar | Matches? | |
160 | // ------------------------------------- | |
161 | // T T yes | |
162 | // T & T yes | |
163 | // T const & T yes | |
164 | // T T & no | |
165 | // T & T & yes | |
166 | // T const & T & no | |
167 | // T T const & no | |
168 | // T & T const & no | |
169 | // T const & T const & yes | |
170 | ||
171 | template<typename T, typename U> | |
172 | struct is_cv_ref_compatible | |
173 | : mpl::true_ | |
174 | {}; | |
175 | ||
176 | template<typename T, typename U> | |
177 | struct is_cv_ref_compatible<T, U &> | |
178 | : mpl::false_ | |
179 | {}; | |
180 | ||
181 | template<typename T, typename U> | |
182 | struct is_cv_ref_compatible<T &, U &> | |
183 | : mpl::bool_<is_const<T>::value == is_const<U>::value> | |
184 | {}; | |
185 | ||
186 | #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) | |
187 | // MSVC-7.1 has lots of problems with array types that have been | |
188 | // deduced. Partially specializing terminal_matches<> on array types | |
189 | // doesn't seem to work. | |
190 | template< | |
191 | typename T | |
192 | , typename U | |
193 | , bool B = is_array<BOOST_PROTO_UNCVREF(T)>::value | |
194 | > | |
195 | struct terminal_array_matches | |
196 | : mpl::false_ | |
197 | {}; | |
198 | ||
199 | template<typename T, typename U, std::size_t M> | |
200 | struct terminal_array_matches<T, U(&)[M], true> | |
201 | : is_convertible<T, U(&)[M]> | |
202 | {}; | |
203 | ||
204 | template<typename T, typename U> | |
205 | struct terminal_array_matches<T, U(&)[proto::N], true> | |
206 | : is_convertible<T, U *> | |
207 | {}; | |
208 | ||
209 | template<typename T, typename U> | |
210 | struct terminal_array_matches<T, U *, true> | |
211 | : is_convertible<T, U *> | |
212 | {}; | |
213 | ||
214 | // terminal_matches | |
215 | template<typename T, typename U> | |
216 | struct terminal_matches | |
217 | : mpl::or_< | |
218 | mpl::and_< | |
219 | is_cv_ref_compatible<T, U> | |
220 | , lambda_matches< | |
221 | BOOST_PROTO_UNCVREF(T) | |
222 | , BOOST_PROTO_UNCVREF(U) | |
223 | > | |
224 | > | |
225 | , terminal_array_matches<T, U> | |
226 | > | |
227 | {}; | |
228 | #else | |
229 | // terminal_matches | |
230 | template<typename T, typename U> | |
231 | struct terminal_matches | |
232 | : mpl::and_< | |
233 | is_cv_ref_compatible<T, U> | |
234 | , lambda_matches< | |
235 | BOOST_PROTO_UNCVREF(T) | |
236 | , BOOST_PROTO_UNCVREF(U) | |
237 | > | |
238 | > | |
239 | {}; | |
240 | ||
241 | template<typename T, std::size_t M> | |
242 | struct terminal_matches<T(&)[M], T(&)[proto::N]> | |
243 | : mpl::true_ | |
244 | {}; | |
245 | ||
246 | template<typename T, std::size_t M> | |
247 | struct terminal_matches<T(&)[M], T *> | |
248 | : mpl::true_ | |
249 | {}; | |
250 | ||
251 | // Avoid ambiguity errors on MSVC | |
252 | #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) | |
253 | template<typename T, std::size_t M> | |
254 | struct terminal_matches<T const (&)[M], T const[M]> | |
255 | : mpl::true_ | |
256 | {}; | |
257 | #endif | |
258 | #endif | |
259 | ||
260 | template<typename T> | |
261 | struct terminal_matches<T, T> | |
262 | : mpl::true_ | |
263 | {}; | |
264 | ||
265 | template<typename T> | |
266 | struct terminal_matches<T &, T> | |
267 | : mpl::true_ | |
268 | {}; | |
269 | ||
270 | template<typename T> | |
271 | struct terminal_matches<T const &, T> | |
272 | : mpl::true_ | |
273 | {}; | |
274 | ||
275 | template<typename T> | |
276 | struct terminal_matches<T, proto::_> | |
277 | : mpl::true_ | |
278 | {}; | |
279 | ||
280 | template<typename T> | |
281 | struct terminal_matches<T, exact<T> > | |
282 | : mpl::true_ | |
283 | {}; | |
284 | ||
285 | template<typename T, typename U> | |
286 | struct terminal_matches<T, proto::convertible_to<U> > | |
287 | : is_convertible<T, U> | |
288 | {}; | |
289 | ||
290 | // matches_ | |
291 | template<typename Expr, typename BasicExpr, typename Grammar> | |
292 | struct matches_ | |
293 | : mpl::false_ | |
294 | {}; | |
295 | ||
296 | template<typename Expr, typename BasicExpr> | |
297 | struct matches_< Expr, BasicExpr, proto::_ > | |
298 | : mpl::true_ | |
299 | {}; | |
300 | ||
301 | template<typename Expr, typename Tag, typename Args1, long N1, typename Args2, long N2> | |
302 | struct matches_< Expr, proto::basic_expr<Tag, Args1, N1>, proto::basic_expr<Tag, Args2, N2> > | |
303 | : vararg_matches< Expr, Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) > | |
304 | {}; | |
305 | ||
306 | template<typename Expr, typename Tag, typename Args1, long N1, typename Args2, long N2> | |
307 | struct matches_< Expr, proto::basic_expr<Tag, Args1, N1>, proto::basic_expr<proto::_, Args2, N2> > | |
308 | : vararg_matches< Expr, Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) > | |
309 | {}; | |
310 | ||
311 | template<typename Expr, typename Tag, typename Args1, typename Args2> | |
312 | struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<Tag, Args2, 0> > | |
313 | : terminal_matches<typename Args1::child0, typename Args2::child0> | |
314 | {}; | |
315 | ||
316 | template<typename Expr, typename Tag, typename Args1, typename Args2, long N2> | |
317 | struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<proto::_, Args2, N2> > | |
318 | : mpl::false_ | |
319 | {}; | |
320 | ||
321 | template<typename Expr, typename Tag, typename Args1, typename Args2> | |
322 | struct matches_< Expr, proto::basic_expr<Tag, Args1, 0>, proto::basic_expr<proto::_, Args2, 0> > | |
323 | : terminal_matches<typename Args1::child0, typename Args2::child0> | |
324 | {}; | |
325 | ||
326 | template<typename Expr, typename Tag, typename Args1, typename Args2> | |
327 | struct matches_< Expr, proto::basic_expr<Tag, Args1, 1>, proto::basic_expr<Tag, Args2, 1> > | |
328 | : matches_< | |
329 | typename detail::expr_traits<typename Args1::child0>::value_type::proto_derived_expr | |
330 | , typename detail::expr_traits<typename Args1::child0>::value_type::proto_grammar | |
331 | , typename Args2::child0::proto_grammar | |
332 | > | |
333 | {}; | |
334 | ||
335 | template<typename Expr, typename Tag, typename Args1, typename Args2> | |
336 | struct matches_< Expr, proto::basic_expr<Tag, Args1, 1>, proto::basic_expr<proto::_, Args2, 1> > | |
337 | : matches_< | |
338 | typename detail::expr_traits<typename Args1::child0>::value_type::proto_derived_expr | |
339 | , typename detail::expr_traits<typename Args1::child0>::value_type::proto_grammar | |
340 | , typename Args2::child0::proto_grammar | |
341 | > | |
342 | {}; | |
343 | ||
344 | #include <boost/proto/detail/and_n.hpp> | |
345 | #include <boost/proto/detail/or_n.hpp> | |
346 | #include <boost/proto/detail/matches_.hpp> | |
347 | #include <boost/proto/detail/vararg_matches_impl.hpp> | |
348 | #include <boost/proto/detail/lambda_matches.hpp> | |
349 | ||
350 | // handle proto::if_ | |
351 | template<typename Expr, typename Tag, typename Args, long Arity, typename If, typename Then, typename Else> | |
352 | struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, proto::if_<If, Then, Else> > | |
353 | : mpl::eval_if_c< | |
354 | static_cast<bool>( | |
355 | remove_reference< | |
356 | typename when<_, If>::template impl<Expr, int, int>::result_type | |
357 | >::type::value | |
358 | ) | |
359 | , matches_<Expr, proto::basic_expr<Tag, Args, Arity>, typename Then::proto_grammar> | |
360 | , matches_<Expr, proto::basic_expr<Tag, Args, Arity>, typename Else::proto_grammar> | |
361 | >::type | |
362 | { | |
363 | typedef | |
364 | typename mpl::if_c< | |
365 | static_cast<bool>( | |
366 | remove_reference< | |
367 | typename when<_, If>::template impl<Expr, int, int>::result_type | |
368 | >::type::value | |
369 | ) | |
370 | , Then | |
371 | , Else | |
372 | >::type | |
373 | which; | |
374 | }; | |
375 | ||
376 | // handle degenerate cases of proto::or_ | |
377 | template<typename Expr, typename BasicExpr> | |
378 | struct matches_<Expr, BasicExpr, or_<> > | |
379 | : mpl::false_ | |
380 | { | |
381 | typedef not_<_> which; | |
382 | }; | |
383 | ||
384 | template<typename Expr, typename BasicExpr, typename G0> | |
385 | struct matches_<Expr, BasicExpr, or_<G0> > | |
386 | : matches_<Expr, BasicExpr, typename G0::proto_grammar> | |
387 | { | |
388 | typedef G0 which; | |
389 | }; | |
390 | ||
391 | // handle degenerate cases of proto::and_ | |
392 | template<typename Expr, typename BasicExpr> | |
393 | struct matches_<Expr, BasicExpr, and_<> > | |
394 | : mpl::true_ | |
395 | {}; | |
396 | ||
397 | template<typename Expr, typename BasicExpr, typename G0> | |
398 | struct matches_<Expr, BasicExpr, and_<G0> > | |
399 | : matches_<Expr, BasicExpr, typename G0::proto_grammar> | |
400 | {}; | |
401 | ||
402 | // handle proto::not_ | |
403 | template<typename Expr, typename BasicExpr, typename Grammar> | |
404 | struct matches_<Expr, BasicExpr, not_<Grammar> > | |
405 | : mpl::not_<matches_<Expr, BasicExpr, typename Grammar::proto_grammar> > | |
406 | {}; | |
407 | ||
408 | // handle proto::switch_ | |
409 | template<typename Expr, typename Tag, typename Args, long Arity, typename Cases, typename Transform> | |
410 | struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, switch_<Cases, Transform> > | |
411 | : matches_< | |
412 | Expr | |
413 | , proto::basic_expr<Tag, Args, Arity> | |
414 | , typename Cases::template case_< | |
415 | typename when<_,Transform>::template impl<Expr,int,int>::result_type | |
416 | >::proto_grammar | |
417 | > | |
418 | { | |
419 | typedef | |
420 | typename Cases::template case_< | |
421 | typename when<_, Transform>::template impl<Expr, int, int>::result_type | |
422 | > | |
423 | which; | |
424 | }; | |
425 | ||
426 | // handle proto::switch_ with the default Transform for specially for better compile times | |
427 | template<typename Expr, typename Tag, typename Args, long Arity, typename Cases> | |
428 | struct matches_<Expr, proto::basic_expr<Tag, Args, Arity>, switch_<Cases> > | |
429 | : matches_< | |
430 | Expr | |
431 | , proto::basic_expr<Tag, Args, Arity> | |
432 | , typename Cases::template case_<Tag>::proto_grammar | |
433 | > | |
434 | { | |
435 | typedef typename Cases::template case_<Tag> which; | |
436 | }; | |
437 | } | |
438 | ||
439 | /// \brief A Boolean metafunction that evaluates whether a given | |
440 | /// expression type matches a grammar. | |
441 | /// | |
442 | /// <tt>matches\<Expr,Grammar\></tt> inherits (indirectly) from | |
443 | /// \c mpl::true_ if <tt>Expr::proto_grammar</tt> matches | |
444 | /// <tt>Grammar::proto_grammar</tt>, and from \c mpl::false_ | |
445 | /// otherwise. | |
446 | /// | |
447 | /// Non-terminal expressions are matched against a grammar | |
448 | /// according to the following rules: | |
449 | /// | |
450 | /// \li The wildcard pattern, \c _, matches any expression. | |
451 | /// \li An expression <tt>expr\<AT, listN\<A0,A1,...An\> \></tt> | |
452 | /// matches a grammar <tt>expr\<BT, listN\<B0,B1,...Bn\> \></tt> | |
453 | /// if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx for | |
454 | /// each \c x in <tt>[0,n)</tt>. | |
455 | /// \li An expression <tt>expr\<AT, listN\<A0,...An,U0,...Um\> \></tt> | |
456 | /// matches a grammar <tt>expr\<BT, listM\<B0,...Bn,vararg\<V\> \> \></tt> | |
457 | /// if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx | |
458 | /// for each \c x in <tt>[0,n)</tt> and if \c Ux matches \c V | |
459 | /// for each \c x in <tt>[0,m)</tt>. | |
460 | /// \li An expression \c E matches <tt>or_\<B0,B1,...Bn\></tt> if \c E | |
461 | /// matches some \c Bx for \c x in <tt>[0,n)</tt>. | |
462 | /// \li An expression \c E matches <tt>and_\<B0,B1,...Bn\></tt> if \c E | |
463 | /// matches all \c Bx for \c x in <tt>[0,n)</tt>. | |
464 | /// \li An expression \c E matches <tt>if_\<T,U,V\></tt> if | |
465 | /// <tt>boost::result_of\<when\<_,T\>(E,int,int)\>::type::value</tt> | |
466 | /// is \c true and \c E matches \c U; or, if | |
467 | /// <tt>boost::result_of\<when\<_,T\>(E,int,int)\>::type::value</tt> | |
468 | /// is \c false and \c E matches \c V. (Note: \c U defaults to \c _ | |
469 | /// and \c V defaults to \c not_\<_\>.) | |
470 | /// \li An expression \c E matches <tt>not_\<T\></tt> if \c E does | |
471 | /// not match \c T. | |
472 | /// \li An expression \c E matches <tt>switch_\<C,T\></tt> if | |
473 | /// \c E matches <tt>C::case_\<boost::result_of\<T(E)\>::type\></tt>. | |
474 | /// (Note: T defaults to <tt>tag_of\<_\>()</tt>.) | |
475 | /// | |
476 | /// A terminal expression <tt>expr\<AT,term\<A\> \></tt> matches | |
477 | /// a grammar <tt>expr\<BT,term\<B\> \></tt> if \c BT is \c AT or | |
478 | /// \c proto::_ and if one of the following is true: | |
479 | /// | |
480 | /// \li \c B is the wildcard pattern, \c _ | |
481 | /// \li \c A is \c B | |
482 | /// \li \c A is <tt>B &</tt> | |
483 | /// \li \c A is <tt>B const &</tt> | |
484 | /// \li \c B is <tt>exact\<A\></tt> | |
485 | /// \li \c B is <tt>convertible_to\<X\></tt> and | |
486 | /// <tt>is_convertible\<A,X\>::value</tt> is \c true. | |
487 | /// \li \c A is <tt>X[M]</tt> or <tt>X(&)[M]</tt> and | |
488 | /// \c B is <tt>X[proto::N]</tt>. | |
489 | /// \li \c A is <tt>X(&)[M]</tt> and \c B is <tt>X(&)[proto::N]</tt>. | |
490 | /// \li \c A is <tt>X[M]</tt> or <tt>X(&)[M]</tt> and | |
491 | /// \c B is <tt>X*</tt>. | |
492 | /// \li \c B lambda-matches \c A (see below). | |
493 | /// | |
494 | /// A type \c B lambda-matches \c A if one of the following is true: | |
495 | /// | |
496 | /// \li \c B is \c A | |
497 | /// \li \c B is the wildcard pattern, \c _ | |
498 | /// \li \c B is <tt>T\<B0,B1,...Bn\></tt> and \c A is | |
499 | /// <tt>T\<A0,A1,...An\></tt> and for each \c x in | |
500 | /// <tt>[0,n)</tt>, \c Ax and \c Bx are types | |
501 | /// such that \c Ax lambda-matches \c Bx | |
502 | template<typename Expr, typename Grammar> | |
503 | struct matches | |
504 | : detail::matches_< | |
505 | typename Expr::proto_derived_expr | |
506 | , typename Expr::proto_grammar | |
507 | , typename Grammar::proto_grammar | |
508 | > | |
509 | {}; | |
510 | ||
511 | /// INTERNAL ONLY | |
512 | /// | |
513 | template<typename Expr, typename Grammar> | |
514 | struct matches<Expr &, Grammar> | |
515 | : detail::matches_< | |
516 | typename Expr::proto_derived_expr | |
517 | , typename Expr::proto_grammar | |
518 | , typename Grammar::proto_grammar | |
519 | > | |
520 | {}; | |
521 | ||
522 | /// \brief A wildcard grammar element that matches any expression, | |
523 | /// and a transform that returns the current expression unchanged. | |
524 | /// | |
525 | /// The wildcard type, \c _, is a grammar element such that | |
526 | /// <tt>matches\<E,_\>::value</tt> is \c true for any expression | |
527 | /// type \c E. | |
528 | /// | |
529 | /// The wildcard can also be used as a stand-in for a template | |
530 | /// argument when matching terminals. For instance, the following | |
531 | /// is a grammar that will match any <tt>std::complex\<\></tt> | |
532 | /// terminal: | |
533 | /// | |
534 | /// \code | |
535 | /// BOOST_MPL_ASSERT(( | |
536 | /// matches< | |
537 | /// terminal<std::complex<double> >::type | |
538 | /// , terminal<std::complex< _ > > | |
539 | /// > | |
540 | /// )); | |
541 | /// \endcode | |
542 | /// | |
543 | /// When used as a transform, \c _ returns the current expression | |
544 | /// unchanged. For instance, in the following, \c _ is used with | |
545 | /// the \c fold\<\> transform to fold the children of a node: | |
546 | /// | |
547 | /// \code | |
548 | /// struct CountChildren | |
549 | /// : or_< | |
550 | /// // Terminals have no children | |
551 | /// when<terminal<_>, mpl::int_<0>()> | |
552 | /// // Use fold<> to count the children of non-terminals | |
553 | /// , otherwise< | |
554 | /// fold< | |
555 | /// _ // <-- fold the current expression | |
556 | /// , mpl::int_<0>() | |
557 | /// , mpl::plus<_state, mpl::int_<1> >() | |
558 | /// > | |
559 | /// > | |
560 | /// > | |
561 | /// {}; | |
562 | /// \endcode | |
563 | struct _ : transform<_> | |
564 | { | |
565 | typedef _ proto_grammar; | |
566 | ||
567 | template<typename Expr, typename State, typename Data> | |
568 | struct impl : transform_impl<Expr, State, Data> | |
569 | { | |
570 | typedef Expr result_type; | |
571 | ||
572 | /// \param expr An expression | |
573 | /// \return \c e | |
574 | BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::expr_param) | |
575 | operator()( | |
576 | typename impl::expr_param e | |
577 | , typename impl::state_param | |
578 | , typename impl::data_param | |
579 | ) const | |
580 | { | |
581 | return e; | |
582 | } | |
583 | }; | |
584 | }; | |
585 | ||
586 | namespace detail | |
587 | { | |
588 | template<typename Expr, typename State, typename Data> | |
589 | struct _and_impl<proto::and_<>, Expr, State, Data> | |
590 | : proto::_::impl<Expr, State, Data> | |
591 | {}; | |
592 | ||
593 | template<typename G0, typename Expr, typename State, typename Data> | |
594 | struct _and_impl<proto::and_<G0>, Expr, State, Data> | |
595 | : proto::when<proto::_, G0>::template impl<Expr, State, Data> | |
596 | {}; | |
597 | } | |
598 | ||
599 | /// \brief Inverts the set of expressions matched by a grammar. When | |
600 | /// used as a transform, \c not_\<\> returns the current expression | |
601 | /// unchanged. | |
602 | /// | |
603 | /// If an expression type \c E does not match a grammar \c G, then | |
604 | /// \c E \e does match <tt>not_\<G\></tt>. For example, | |
605 | /// <tt>not_\<terminal\<_\> \></tt> will match any non-terminal. | |
606 | template<typename Grammar> | |
607 | struct not_ : transform<not_<Grammar> > | |
608 | { | |
609 | typedef not_ proto_grammar; | |
610 | ||
611 | template<typename Expr, typename State, typename Data> | |
612 | struct impl : transform_impl<Expr, State, Data> | |
613 | { | |
614 | typedef Expr result_type; | |
615 | ||
616 | /// \param e An expression | |
617 | /// \pre <tt>matches\<Expr,not_\>::value</tt> is \c true. | |
618 | /// \return \c e | |
619 | BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(result_type, typename impl::expr_param) | |
620 | operator()( | |
621 | typename impl::expr_param e | |
622 | , typename impl::state_param | |
623 | , typename impl::data_param | |
624 | ) const | |
625 | { | |
626 | return e; | |
627 | } | |
628 | }; | |
629 | }; | |
630 | ||
631 | /// \brief Used to select one grammar or another based on the result | |
632 | /// of a compile-time Boolean. When used as a transform, \c if_\<\> | |
633 | /// selects between two transforms based on a compile-time Boolean. | |
634 | /// | |
635 | /// When <tt>if_\<If,Then,Else\></tt> is used as a grammar, \c If | |
636 | /// must be a Proto transform and \c Then and \c Else must be grammars. | |
637 | /// An expression type \c E matches <tt>if_\<If,Then,Else\></tt> if | |
638 | /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt> | |
639 | /// is \c true and \c E matches \c U; or, if | |
640 | /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt> | |
641 | /// is \c false and \c E matches \c V. | |
642 | /// | |
643 | /// The template parameter \c Then defaults to \c _ | |
644 | /// and \c Else defaults to \c not\<_\>, so an expression type \c E | |
645 | /// will match <tt>if_\<If\></tt> if and only if | |
646 | /// <tt>boost::result_of\<when\<_,If\>(E,int,int)\>::type::value</tt> | |
647 | /// is \c true. | |
648 | /// | |
649 | /// \code | |
650 | /// // A grammar that only matches integral terminals, | |
651 | /// // using is_integral<> from Boost.Type_traits. | |
652 | /// struct IsIntegral | |
653 | /// : and_< | |
654 | /// terminal<_> | |
655 | /// , if_< is_integral<_value>() > | |
656 | /// > | |
657 | /// {}; | |
658 | /// \endcode | |
659 | /// | |
660 | /// When <tt>if_\<If,Then,Else\></tt> is used as a transform, \c If, | |
661 | /// \c Then and \c Else must be Proto transforms. When applying | |
662 | /// the transform to an expression \c E, state \c S and data \c V, | |
663 | /// if <tt>boost::result_of\<when\<_,If\>(E,S,V)\>::type::value</tt> | |
664 | /// is \c true then the \c Then transform is applied; otherwise | |
665 | /// the \c Else transform is applied. | |
666 | /// | |
667 | /// \code | |
668 | /// // Match a terminal. If the terminal is integral, return | |
669 | /// // mpl::true_; otherwise, return mpl::false_. | |
670 | /// struct IsIntegral2 | |
671 | /// : when< | |
672 | /// terminal<_> | |
673 | /// , if_< | |
674 | /// is_integral<_value>() | |
675 | /// , mpl::true_() | |
676 | /// , mpl::false_() | |
677 | /// > | |
678 | /// > | |
679 | /// {}; | |
680 | /// \endcode | |
681 | template< | |
682 | typename If | |
683 | , typename Then // = _ | |
684 | , typename Else // = not_<_> | |
685 | > | |
686 | struct if_ : transform<if_<If, Then, Else> > | |
687 | { | |
688 | typedef if_ proto_grammar; | |
689 | ||
690 | template<typename Expr, typename State, typename Data> | |
691 | struct impl : transform_impl<Expr, State, Data> | |
692 | { | |
693 | typedef | |
694 | typename when<_, If>::template impl<Expr, State, Data>::result_type | |
695 | condition; | |
696 | ||
697 | typedef | |
698 | typename mpl::if_c< | |
699 | static_cast<bool>(remove_reference<condition>::type::value) | |
700 | , when<_, Then> | |
701 | , when<_, Else> | |
702 | >::type | |
703 | which; | |
704 | ||
705 | typedef typename which::template impl<Expr, State, Data>::result_type result_type; | |
706 | ||
707 | /// \param e An expression | |
708 | /// \param s The current state | |
709 | /// \param d A data of arbitrary type | |
710 | /// \return <tt>which::impl<Expr, State, Data>()(e, s, d)</tt> | |
711 | result_type operator ()( | |
712 | typename impl::expr_param e | |
713 | , typename impl::state_param s | |
714 | , typename impl::data_param d | |
715 | ) const | |
716 | { | |
717 | return typename which::template impl<Expr, State, Data>()(e, s, d); | |
718 | } | |
719 | }; | |
720 | }; | |
721 | ||
722 | /// \brief For matching one of a set of alternate grammars. Alternates | |
723 | /// tried in order to avoid ambiguity. When used as a transform, \c or_\<\> | |
724 | /// applies the transform associated with the first grammar that matches | |
725 | /// the expression. | |
726 | /// | |
727 | /// An expression type \c E matches <tt>or_\<B0,B1,...Bn\></tt> if \c E | |
728 | /// matches any \c Bx for \c x in <tt>[0,n)</tt>. | |
729 | /// | |
730 | /// When applying <tt>or_\<B0,B1,...Bn\></tt> as a transform with an | |
731 | /// expression \c e of type \c E, state \c s and data \c d, it is | |
732 | /// equivalent to <tt>Bx()(e, s, d)</tt>, where \c x is the lowest | |
733 | /// number such that <tt>matches\<E,Bx\>::value</tt> is \c true. | |
734 | template<BOOST_PROTO_LOGICAL_typename_G> | |
735 | struct or_ : transform<or_<BOOST_PROTO_LOGICAL_G> > | |
736 | { | |
737 | typedef or_ proto_grammar; | |
738 | ||
739 | /// \param e An expression | |
740 | /// \param s The current state | |
741 | /// \param d A data of arbitrary type | |
742 | /// \pre <tt>matches\<Expr,or_\>::value</tt> is \c true. | |
743 | /// \return <tt>which()(e, s, d)</tt>, where <tt>which</tt> is the | |
744 | /// sub-grammar that matched <tt>Expr</tt>. | |
745 | ||
746 | template<typename Expr, typename State, typename Data> | |
747 | struct impl | |
748 | : detail::matches_< | |
749 | typename Expr::proto_derived_expr | |
750 | , typename Expr::proto_grammar | |
751 | , or_ | |
752 | >::which::template impl<Expr, State, Data> | |
753 | {}; | |
754 | ||
755 | template<typename Expr, typename State, typename Data> | |
756 | struct impl<Expr &, State, Data> | |
757 | : detail::matches_< | |
758 | typename Expr::proto_derived_expr | |
759 | , typename Expr::proto_grammar | |
760 | , or_ | |
761 | >::which::template impl<Expr &, State, Data> | |
762 | {}; | |
763 | }; | |
764 | ||
765 | /// \brief For matching all of a set of grammars. When used as a | |
766 | /// transform, \c and_\<\> applies the transforms associated with | |
767 | /// the each grammar in the set, and returns the result of the last. | |
768 | /// | |
769 | /// An expression type \c E matches <tt>and_\<B0,B1,...Bn\></tt> if \c E | |
770 | /// matches all \c Bx for \c x in <tt>[0,n)</tt>. | |
771 | /// | |
772 | /// When applying <tt>and_\<B0,B1,...Bn\></tt> as a transform with an | |
773 | /// expression \c e, state \c s and data \c d, it is | |
774 | /// equivalent to <tt>(B0()(e, s, d),B1()(e, s, d),...Bn()(e, s, d))</tt>. | |
775 | template<BOOST_PROTO_LOGICAL_typename_G> | |
776 | struct and_ : transform<and_<BOOST_PROTO_LOGICAL_G> > | |
777 | { | |
778 | typedef and_ proto_grammar; | |
779 | ||
780 | template<typename Expr, typename State, typename Data> | |
781 | struct impl | |
782 | : detail::_and_impl<and_, Expr, State, Data> | |
783 | {}; | |
784 | }; | |
785 | ||
786 | /// \brief For matching one of a set of alternate grammars, which | |
787 | /// are looked up based on some property of an expression. The | |
788 | /// property on which to dispatch is specified by the \c Transform | |
789 | /// template parameter, which defaults to <tt>tag_of\<_\>()</tt>. | |
790 | /// That is, when the \c Trannsform is not specified, the alternate | |
791 | /// grammar is looked up using the tag type of the current expression. | |
792 | /// | |
793 | /// When used as a transform, \c switch_\<\> applies the transform | |
794 | /// associated with the grammar that matches the expression. | |
795 | /// | |
796 | /// \note \c switch_\<\> is functionally identical to \c or_\<\> but | |
797 | /// is often more efficient. It does a fast, O(1) lookup using the | |
798 | /// result of the specified transform to find a sub-grammar that may | |
799 | /// potentially match the expression. | |
800 | /// | |
801 | /// An expression type \c E matches <tt>switch_\<C,T\></tt> if \c E | |
802 | /// matches <tt>C::case_\<boost::result_of\<T(E)\>::type\></tt>. | |
803 | /// | |
804 | /// When applying <tt>switch_\<C,T\></tt> as a transform with an | |
805 | /// expression \c e of type \c E, state \c s of type \S and data | |
806 | /// \c d of type \c D, it is equivalent to | |
807 | /// <tt>C::case_\<boost::result_of\<T(E,S,D)\>::type\>()(e, s, d)</tt>. | |
808 | template<typename Cases, typename Transform> | |
809 | struct switch_ : transform<switch_<Cases, Transform> > | |
810 | { | |
811 | typedef switch_ proto_grammar; | |
812 | ||
813 | template<typename Expr, typename State, typename Data> | |
814 | struct impl | |
815 | : Cases::template case_< | |
816 | typename when<_, Transform>::template impl<Expr, State, Data>::result_type | |
817 | >::template impl<Expr, State, Data> | |
818 | {}; | |
819 | }; | |
820 | ||
821 | /// INTERNAL ONLY (This is merely a compile-time optimization for the common case) | |
822 | /// | |
823 | template<typename Cases> | |
824 | struct switch_<Cases> : transform<switch_<Cases> > | |
825 | { | |
826 | typedef switch_ proto_grammar; | |
827 | ||
828 | template<typename Expr, typename State, typename Data> | |
829 | struct impl | |
830 | : Cases::template case_<typename Expr::proto_tag>::template impl<Expr, State, Data> | |
831 | {}; | |
832 | ||
833 | template<typename Expr, typename State, typename Data> | |
834 | struct impl<Expr &, State, Data> | |
835 | : Cases::template case_<typename Expr::proto_tag>::template impl<Expr &, State, Data> | |
836 | {}; | |
837 | }; | |
838 | ||
839 | /// \brief For forcing exact matches of terminal types. | |
840 | /// | |
841 | /// By default, matching terminals ignores references and | |
842 | /// cv-qualifiers. For instance, a terminal expression of | |
843 | /// type <tt>terminal\<int const &\>::type</tt> will match | |
844 | /// the grammar <tt>terminal\<int\></tt>. If that is not | |
845 | /// desired, you can force an exact match with | |
846 | /// <tt>terminal\<exact\<int\> \></tt>. This will only | |
847 | /// match integer terminals where the terminal is held by | |
848 | /// value. | |
849 | template<typename T> | |
850 | struct exact | |
851 | {}; | |
852 | ||
853 | /// \brief For matching terminals that are convertible to | |
854 | /// a type. | |
855 | /// | |
856 | /// Use \c convertible_to\<\> to match a terminal that is | |
857 | /// convertible to some type. For example, the grammar | |
858 | /// <tt>terminal\<convertible_to\<int\> \></tt> will match | |
859 | /// any terminal whose argument is convertible to an integer. | |
860 | /// | |
861 | /// \note The trait \c is_convertible\<\> from Boost.Type_traits | |
862 | /// is used to determinal convertibility. | |
863 | template<typename T> | |
864 | struct convertible_to | |
865 | {}; | |
866 | ||
867 | /// \brief For matching a Grammar to a variable number of | |
868 | /// sub-expressions. | |
869 | /// | |
870 | /// An expression type <tt>expr\<AT, listN\<A0,...An,U0,...Um\> \></tt> | |
871 | /// matches a grammar <tt>expr\<BT, listM\<B0,...Bn,vararg\<V\> \> \></tt> | |
872 | /// if \c BT is \c _ or \c AT, and if \c Ax matches \c Bx | |
873 | /// for each \c x in <tt>[0,n)</tt> and if \c Ux matches \c V | |
874 | /// for each \c x in <tt>[0,m)</tt>. | |
875 | /// | |
876 | /// For example: | |
877 | /// | |
878 | /// \code | |
879 | /// // Match any function call expression, irregardless | |
880 | /// // of the number of function arguments: | |
881 | /// struct Function | |
882 | /// : function< vararg<_> > | |
883 | /// {}; | |
884 | /// \endcode | |
885 | /// | |
886 | /// When used as a transform, <tt>vararg\<G\></tt> applies | |
887 | /// <tt>G</tt>'s transform. | |
888 | template<typename Grammar> | |
889 | struct vararg | |
890 | : Grammar | |
891 | { | |
892 | /// INTERNAL ONLY | |
893 | typedef void proto_is_vararg_; | |
894 | }; | |
895 | ||
896 | /// INTERNAL ONLY | |
897 | /// | |
898 | template<BOOST_PROTO_LOGICAL_typename_G> | |
899 | struct is_callable<or_<BOOST_PROTO_LOGICAL_G> > | |
900 | : mpl::true_ | |
901 | {}; | |
902 | ||
903 | /// INTERNAL ONLY | |
904 | /// | |
905 | template<BOOST_PROTO_LOGICAL_typename_G> | |
906 | struct is_callable<and_<BOOST_PROTO_LOGICAL_G> > | |
907 | : mpl::true_ | |
908 | {}; | |
909 | ||
910 | /// INTERNAL ONLY | |
911 | /// | |
912 | template<typename Grammar> | |
913 | struct is_callable<not_<Grammar> > | |
914 | : mpl::true_ | |
915 | {}; | |
916 | ||
917 | /// INTERNAL ONLY | |
918 | /// | |
919 | template<typename If, typename Then, typename Else> | |
920 | struct is_callable<if_<If, Then, Else> > | |
921 | : mpl::true_ | |
922 | {}; | |
923 | ||
924 | /// INTERNAL ONLY | |
925 | /// | |
926 | template<typename Grammar> | |
927 | struct is_callable<vararg<Grammar> > | |
928 | : mpl::true_ | |
929 | {}; | |
930 | ||
931 | /// INTERNAL ONLY | |
932 | /// | |
933 | template<typename Cases, typename Transform> | |
934 | struct is_callable<switch_<Cases, Transform> > | |
935 | : mpl::true_ | |
936 | {}; | |
937 | ||
938 | }} | |
939 | ||
940 | #undef BOOST_PROTO_LOGICAL_typename_G | |
941 | #undef BOOST_PROTO_LOGICAL_G | |
942 | ||
943 | #if defined(_MSC_VER) | |
944 | # pragma warning(pop) | |
945 | #endif | |
946 | ||
947 | #endif |