source: NonGTP/Boost/boost/spirit/dynamic/impl/switch.ipp @ 857

Revision 857, 21.0 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2003 Hartmut Kaiser
3    http://spirit.sourceforge.net/
4
5    Use, modification and distribution is subject to the Boost Software
6    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7    http://www.boost.org/LICENSE_1_0.txt)
8=============================================================================*/
9#ifndef BOOST_SPIRIT_SWITCH_IPP
10#define BOOST_SPIRIT_SWITCH_IPP
11
12#include <boost/mpl/if.hpp>
13#include <boost/type_traits/is_same.hpp>
14#include <boost/static_assert.hpp>
15
16#include <boost/preprocessor/cat.hpp>
17#include <boost/preprocessor/inc.hpp>
18#include <boost/preprocessor/repeat.hpp>
19#include <boost/preprocessor/repeat_from_to.hpp>
20
21#include <boost/spirit/core/parser.hpp>
22#include <boost/spirit/core/primitives/primitives.hpp>
23#include <boost/spirit/core/composite/composite.hpp>
24#include <boost/spirit/meta/as_parser.hpp>
25
26#include <boost/spirit/phoenix/actor.hpp>
27#include <boost/spirit/phoenix/tuples.hpp>
28
29///////////////////////////////////////////////////////////////////////////////
30namespace boost { namespace spirit {
31
32// forward declaration
33template <int N, typename ParserT, bool IsDefault> struct case_parser;
34
35///////////////////////////////////////////////////////////////////////////////
36namespace impl {
37
38///////////////////////////////////////////////////////////////////////////////
39//  parse helper functions
40template <typename ParserT, typename ScannerT>
41inline typename parser_result<ParserT, ScannerT>::type
42delegate_parse(ParserT const &p, ScannerT const &scan,
43    typename ScannerT::iterator_t const save)
44{
45    typedef typename parser_result<ParserT, ScannerT>::type result_t;
46
47    result_t result (p.subject().parse(scan));
48    if (!result)
49        scan.first = save;
50    return result;
51}
52
53///////////////////////////////////////////////////////////////////////////////
54//  General default case handling (no default_p case branch given).
55//  First try to match the current parser node (if the condition value is
56//  matched) and, if that fails, return a no_match
57template <int N, bool IsDefault, bool HasDefault>
58struct default_delegate_parse {
59
60    template <
61        typename ParserT, typename DefaultT,
62        typename ValueT, typename ScannerT
63    >
64    static typename parser_result<ParserT, ScannerT>::type
65    parse (ValueT const &value, ParserT const &p, DefaultT const &,
66        ScannerT const &scan, typename ScannerT::iterator_t const save)
67    {
68        if (value == N)
69            return delegate_parse(p, scan, save);
70        return scan.no_match();
71    }
72};
73
74//  The current case parser node is the default parser.
75//  Ignore the given case value and try to match the given default parser.
76template <int N, bool HasDefault>
77struct default_delegate_parse<N, true, HasDefault> {
78
79    template <
80        typename ParserT, typename DefaultT,
81        typename ValueT, typename ScannerT
82    >
83    static typename parser_result<ParserT, ScannerT>::type
84    parse (ValueT const& /*value*/, ParserT const &, DefaultT const &d,
85        ScannerT const &scan, typename ScannerT::iterator_t const save)
86    {
87        //  Since there is a default_p case branch defined, the corresponding
88        //  parser shouldn't be the nothing_parser
89        BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value));
90        return delegate_parse(d, scan, save);
91    }
92};
93
94//  The current case parser node is not the default parser, but there is a
95//  default_p branch given inside the switch_p parser.
96//  First try to match the current parser node (if the condition value is
97//  matched) and, if that fails, match the given default_p parser.
98template <int N>
99struct default_delegate_parse<N, false, true> {
100
101    template <
102        typename ParserT, typename DefaultT,
103        typename ValueT, typename ScannerT
104    >
105    static typename parser_result<ParserT, ScannerT>::type
106    parse (ValueT const &value, ParserT const &p, DefaultT const &d,
107        ScannerT const &scan, typename ScannerT::iterator_t const save)
108    {
109        //  Since there is a default_p case branch defined, the corresponding
110        //  parser shouldn't be the nothing_parser
111        BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value));
112        if (value == N)
113            return delegate_parse(p, scan, save);
114
115        return delegate_parse(d, scan, save);
116    }
117};
118
119///////////////////////////////////////////////////////////////////////////////
120//  Look through the case parser chain to test, if there is a default case
121//  branch defined (returned by 'value').
122template <typename CaseT, bool IsSimple = CaseT::is_simple>
123struct default_case;
124
125////////////////////////////////////////
126template <typename ResultT, bool IsDefault>
127struct get_default_parser {
128
129    template <typename ParserT>
130    static ResultT
131    get(parser<ParserT> const &p)
132    {
133        return default_case<typename ParserT::derived_t::left_t>::
134            get(p.derived().left());
135    }
136};
137
138template <typename ResultT>
139struct get_default_parser<ResultT, true> {
140
141    template <typename ParserT>
142    static ResultT
143    get(parser<ParserT> const &p) { return p.derived().right(); }
144};
145
146////////////////////////////////////////
147template <typename CaseT, bool IsSimple>
148struct default_case {
149
150    //  The 'value' constant is true, if the current case_parser or one of its
151    //  left siblings is a default_p generated case_parser.
152    BOOST_STATIC_CONSTANT(bool, value =
153        (CaseT::is_default || default_case<typename CaseT::left_t>::value));
154
155    //  The 'is_epsilon' constant is true, if the current case_parser or one of
156    //  its left siblings is a default_p generated parser with an attached
157    //  epsilon_p (this is generated by the plain default_p).
158    BOOST_STATIC_CONSTANT(bool, is_epsilon = (
159        (CaseT::is_default && CaseT::is_epsilon) ||
160            default_case<typename CaseT::left_t>::is_epsilon
161    ));
162
163    //  The computed 'type' represents the type of the default case branch
164    //  parser (if there is one) or nothing_parser (if there isn't any default
165    //  case branch).
166    typedef typename boost::mpl::if_c<
167            CaseT::is_default, typename CaseT::right_embed_t,
168            typename default_case<typename CaseT::left_t>::type
169        >::type type;
170
171    //  The get function returns the parser attached to the default case branch
172    //  (if there is one) or an instance of a nothing_parser (if there isn't
173    //  any default case branch).
174    template <typename ParserT>
175    static type
176    get(parser<ParserT> const &p)
177    { return get_default_parser<type, CaseT::is_default>::get(p); }
178};
179
180////////////////////////////////////////
181template <typename ResultT, bool IsDefault>
182struct get_default_parser_simple {
183
184    template <typename ParserT>
185    static ResultT
186    get(parser<ParserT> const &p) { return p.derived(); }
187};
188
189template <typename ResultT>
190struct get_default_parser_simple<ResultT, false> {
191
192    template <typename ParserT>
193    static nothing_parser
194    get(parser<ParserT> const &) { return nothing_p; }
195};
196
197////////////////////////////////////////
198//  Specialization of the default_case template for the last (leftmost) element
199//  of the case parser chain.
200template <typename CaseT>
201struct default_case<CaseT, true> {
202
203    //  The 'value' and 'is_epsilon' constant, the 'type' type and the function
204    //  'get' are described above.
205
206    BOOST_STATIC_CONSTANT(bool, value = CaseT::is_default);
207    BOOST_STATIC_CONSTANT(bool, is_epsilon = (
208        CaseT::is_default && CaseT::is_epsilon
209    ));
210
211    typedef typename boost::mpl::if_c<
212            CaseT::is_default, CaseT, nothing_parser
213        >::type type;
214
215    template <typename ParserT>
216    static type
217    get(parser<ParserT> const &p)
218    { return get_default_parser_simple<type, value>::get(p); }
219};
220
221///////////////////////////////////////////////////////////////////////////////
222//  The case_chain template calculates recursivly the depth of the left
223//  subchain of the given case branch node.
224template <typename CaseT, bool IsSimple = CaseT::is_simple>
225struct case_chain {
226
227    BOOST_STATIC_CONSTANT(int, depth = (
228        case_chain<typename CaseT::left_t>::depth + 1
229    ));
230};
231
232template <typename CaseT>
233struct case_chain<CaseT, true> {
234
235    BOOST_STATIC_CONSTANT(int, depth = 0);
236};
237
238///////////////////////////////////////////////////////////////////////////////
239//  The chain_parser template is used to extract the type and the instance of
240//  a left or a right parser, burried arbitrary deep inside the case parser
241//  chain.
242template <int Depth, typename CaseT>
243struct chain_parser {
244
245    typedef typename CaseT::left_t our_left_t;
246
247    typedef typename chain_parser<Depth-1, our_left_t>::left_t  left_t;
248    typedef typename chain_parser<Depth-1, our_left_t>::right_t right_t;
249
250    static left_t
251    left(CaseT const &p)
252    { return chain_parser<Depth-1, our_left_t>::left(p.left()); }
253
254    static right_t
255    right(CaseT const &p)
256    { return chain_parser<Depth-1, our_left_t>::right(p.left()); }
257};
258
259template <typename CaseT>
260struct chain_parser<1, CaseT> {
261
262    typedef typename CaseT::left_t  left_t;
263    typedef typename CaseT::right_t right_t;
264
265    static left_t left(CaseT const &p) { return p.left(); }
266    static right_t right(CaseT const &p) { return p.right(); }
267};
268
269template <typename CaseT>
270struct chain_parser<0, CaseT>;      // shouldn't be instantiated
271
272///////////////////////////////////////////////////////////////////////////////
273//  Type computing meta function for calculating the type of the return value
274//  of the used conditional switch expression
275template <typename TargetT, typename ScannerT>
276struct condition_result {
277
278    typedef typename TargetT::template result<ScannerT>::type type;
279};
280
281///////////////////////////////////////////////////////////////////////////////
282template <typename LeftT, typename RightT, bool IsDefault>
283struct compound_case_parser
284:   public binary<LeftT, RightT,
285        parser<compound_case_parser<LeftT, RightT, IsDefault> > >
286{
287    typedef compound_case_parser<LeftT, RightT, IsDefault>    self_t;
288    typedef binary_parser_category                  parser_category_t;
289    typedef binary<LeftT, RightT, parser<self_t> >  base_t;
290
291    BOOST_STATIC_CONSTANT(int, value = RightT::value);
292    BOOST_STATIC_CONSTANT(bool, is_default = IsDefault);
293    BOOST_STATIC_CONSTANT(bool, is_simple = false);
294    BOOST_STATIC_CONSTANT(bool, is_epsilon = (
295        is_default &&
296            boost::is_same<typename RightT::subject_t, epsilon_parser>::value
297    ));
298
299    compound_case_parser(parser<LeftT> const &lhs, parser<RightT> const &rhs)
300    :   base_t(lhs.derived(), rhs.derived())
301    {}
302
303    template <typename ScannerT>
304    struct result
305    {
306        typedef typename match_result<ScannerT, nil_t>::type type;
307    };
308
309    template <typename ScannerT, typename CondT>
310    typename parser_result<self_t, ScannerT>::type
311    parse(ScannerT const& scan, CondT const &cond) const;
312
313    template <int N1, typename ParserT1, bool IsDefault1>
314    compound_case_parser<
315        self_t, case_parser<N1, ParserT1, IsDefault1>, IsDefault1
316    >
317    operator, (case_parser<N1, ParserT1, IsDefault1> const &p) const
318    {
319        //  If the following compile time assertion fires, you've probably used
320        //  more than one default_p case inside the switch_p parser construct.
321        BOOST_STATIC_ASSERT(!default_case<self_t>::value || !IsDefault1);
322
323        //  If this compile time assertion fires, you've probably want to use
324        //  more case_p/default_p case branches, than possible.
325        BOOST_STATIC_ASSERT(
326            case_chain<self_t>::depth < BOOST_SPIRIT_SWITCH_CASE_LIMIT
327        );
328
329        typedef case_parser<N1, ParserT1, IsDefault1> right_t;
330        return compound_case_parser<self_t, right_t, IsDefault1>(*this, p);
331    }
332};
333
334///////////////////////////////////////////////////////////////////////////////
335//  The parse_switch::do_ functions dispatch to the correct parser, which is
336//  selected through the given conditional switch value.
337template <int Value, int Depth, bool IsDefault>
338struct parse_switch;
339
340///////////////////////////////////////////////////////////////////////////////
341//
342//  The following generates a couple of parse_switch template specializations
343//  with an increasing number of handled case branches (for 1..N).
344//
345//      template <int Value, bool IsDefault>
346//      struct parse_switch<Value, N, IsDefault> {
347//
348//          template <typename ParserT, typename ScannerT>
349//          static typename parser_result<ParserT, ScannerT>::type
350//          do_(ParserT const &p, ScannerT const &scan, long cond_value,
351//              typename ScannerT::iterator_t const &save)
352//          {
353//              typedef ParserT left_t0;
354//              typedef typename left_t0::left left_t1;
355//              ...
356//
357//              switch (cond_value) {
358//              case left_tN::value:
359//                  return delegate_parse(chain_parser<
360//                          case_chain<ParserT>::depth, ParserT
361//                      >::left(p), scan, save);
362//              ...
363//              case left_t1::value:
364//                  return delegate_parse(chain_parser<
365//                          1, left_t1
366//                      >::right(p.left()), scan, save);
367//
368//              case left_t0::value:
369//              default:
370//                  typedef default_case<ParserT> default_t;
371//                  typedef default_delegate_parse<
372//                              Value, IsDefault, default_t::value>
373//                      default_parse_t;
374//
375//                  return default_parse_t::parse(cond_value, p.right(),
376//                      default_t::get(p), scan, save);
377//              }
378//          }
379//      };
380//
381///////////////////////////////////////////////////////////////////////////////
382#define BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS(z, N, _)                         \
383    typedef typename BOOST_PP_CAT(left_t, N)::left_t                        \
384        BOOST_PP_CAT(left_t, BOOST_PP_INC(N));                              \
385    /**/
386
387#define BOOST_SPIRIT_PARSE_SWITCH_CASES(z, N, _)                            \
388    case (long)(BOOST_PP_CAT(left_t, N)::value):                            \
389        return delegate_parse(chain_parser<N, left_t1>::right(p.left()),    \
390            scan, save);                                                    \
391    /**/
392
393#define BOOST_SPIRIT_PARSE_SWITCHES(z, N, _)                                \
394    template <int Value, bool IsDefault>                                    \
395    struct parse_switch<Value, BOOST_PP_INC(N), IsDefault> {                \
396                                                                            \
397        template <typename ParserT, typename ScannerT>                      \
398        static typename parser_result<ParserT, ScannerT>::type              \
399        do_(ParserT const &p, ScannerT const &scan, long cond_value,        \
400            typename ScannerT::iterator_t const &save)                      \
401        {                                                                   \
402            typedef ParserT left_t0;                                        \
403            BOOST_PP_REPEAT_FROM_TO_ ## z(0, BOOST_PP_INC(N),               \
404                BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS, _)                      \
405                                                                            \
406            switch (cond_value) {                                           \
407            case (long)(BOOST_PP_CAT(left_t, BOOST_PP_INC(N))::value):      \
408                return delegate_parse(                                      \
409                    chain_parser<                                           \
410                        case_chain<ParserT>::depth, ParserT                 \
411                    >::left(p), scan, save);                                \
412                                                                            \
413            BOOST_PP_REPEAT_FROM_TO_ ## z(1, BOOST_PP_INC(N),               \
414                BOOST_SPIRIT_PARSE_SWITCH_CASES, _)                         \
415                                                                            \
416            case (long)(left_t0::value):                                    \
417            default:                                                        \
418                typedef default_case<ParserT> default_t;                    \
419                typedef                                                     \
420                    default_delegate_parse<Value, IsDefault, default_t::value> \
421                    default_parse_t;                                        \
422                                                                            \
423                return default_parse_t::parse(cond_value, p.right(),        \
424                    default_t::get(p), scan, save);                         \
425            }                                                               \
426        }                                                                   \
427    };                                                                      \
428    /**/
429
430BOOST_PP_REPEAT(BOOST_PP_DEC(BOOST_SPIRIT_SWITCH_CASE_LIMIT),
431    BOOST_SPIRIT_PARSE_SWITCHES, _)
432
433#undef BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS
434#undef BOOST_SPIRIT_PARSE_SWITCH_CASES
435#undef BOOST_SPIRIT_PARSE_SWITCHES
436///////////////////////////////////////////////////////////////////////////////
437
438template <typename LeftT, typename RightT, bool IsDefault>
439template <typename ScannerT, typename CondT>
440inline typename parser_result<
441    compound_case_parser<LeftT, RightT, IsDefault>, ScannerT
442>::type
443compound_case_parser<LeftT, RightT, IsDefault>::
444    parse(ScannerT const& scan, CondT const &cond) const
445{
446    scan.at_end();    // allow skipper to take effect
447    return parse_switch<value, case_chain<self_t>::depth, is_default>::
448        do_(*this, scan, cond(scan), scan.first);
449}
450
451///////////////////////////////////////////////////////////////////////////////
452//  The switch condition is to be evaluated from a parser result value.
453template <typename ParserT>
454struct cond_functor {
455
456    typedef cond_functor<ParserT> self_t;
457
458    cond_functor(ParserT const &p_)
459    :   p(p_)
460    {}
461
462    template <typename ScannerT>
463    struct result
464    {
465        typedef typename parser_result<ParserT, ScannerT>::type::attr_t type;
466    };
467
468    template <typename ScannerT>
469    typename condition_result<self_t, ScannerT>::type
470    operator()(ScannerT const &scan) const
471    {
472        typedef typename parser_result<ParserT, ScannerT>::type result_t;
473        typedef typename result_t::attr_t attr_t;
474
475        result_t result(p.parse(scan));
476        return !result ? attr_t() : result.value();
477    }
478
479    typename ParserT::embed_t p;
480};
481
482template <typename ParserT>
483struct make_cond_functor {
484
485    typedef as_parser<ParserT> as_parser_t;
486
487    static cond_functor<typename as_parser_t::type>
488    do_(ParserT const &cond)
489    {
490        return cond_functor<typename as_parser_t::type>(
491            as_parser_t::convert(cond));
492    }
493};
494
495///////////////////////////////////////////////////////////////////////////////
496//  The switch condition is to be evaluated from a phoenix actor
497template <typename ActorT>
498struct cond_actor {
499
500    typedef cond_actor<ActorT> self_t;
501
502    cond_actor(ActorT const &actor_)
503    :   actor(actor_)
504    {}
505
506    template <typename ScannerT>
507    struct result
508    {
509        typedef typename phoenix::actor_result<ActorT, phoenix::tuple<> >::type
510            type;
511    };
512
513    template <typename ScannerT>
514    typename condition_result<self_t, ScannerT>::type
515    operator()(ScannerT const& /*scan*/) const
516    {
517        return actor();
518    }
519
520    ActorT const &actor;
521};
522
523template <typename ActorT>
524struct make_cond_functor<phoenix::actor<ActorT> > {
525
526    static cond_actor<phoenix::actor<ActorT> >
527    do_(phoenix::actor<ActorT> const &actor)
528    {
529        return cond_actor<phoenix::actor<ActorT> >(actor);
530    }
531};
532
533///////////////////////////////////////////////////////////////////////////////
534//  The switch condition is to be taken directly from the input stream
535struct get_next_token_cond {
536
537    typedef get_next_token_cond self_t;
538
539    template <typename ScannerT>
540    struct result
541    {
542        typedef typename ScannerT::value_t type;
543    };
544
545    template <typename ScannerT>
546    typename condition_result<self_t, ScannerT>::type
547    operator()(ScannerT const &scan) const
548    {
549        typename ScannerT::value_t val(*scan);
550        ++scan.first;
551        return val;
552    }
553};
554
555template <>
556struct make_cond_functor<get_next_token_cond> {
557
558    static get_next_token_cond
559    do_(get_next_token_cond const &cond)
560    {
561        return cond;
562    }
563};
564
565///////////////////////////////////////////////////////////////////////////////
566}   // namespace impl
567}}  // namespace boost::spirit
568
569#endif  // BOOST_SPIRIT_SWITCH_IPP
Note: See TracBrowser for help on using the repository browser.