1 /*=============================================================================
2     Copyright (c) 2002-2003 Joel de Guzman
3     Copyright (c) 2002 Juan Carlos Arevalo-Baeza
4     Copyright (c) 2002-2003 Martin Wille
5     http://spirit.sourceforge.net/
6 
7     Use, modification and distribution is subject to the Boost Software
8     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9     http://www.boost.org/LICENSE_1_0.txt)
10 =============================================================================*/
11 #ifndef BOOST_SPIRIT_IF_HPP
12 #define BOOST_SPIRIT_IF_HPP
13 
14 #include <boost/spirit/core/parser.hpp>
15 #include <boost/spirit/core/composite/composite.hpp>
16 #include <boost/spirit/dynamic/impl/conditions.ipp>
17 
18 namespace boost { namespace spirit {
19 
20     namespace impl {
21 
22     //////////////////////////////////
23     // if-else-parser, holds two alternative parsers and a conditional functor
24     // that selects between them.
25     template <typename ParsableTrueT, typename ParsableFalseT, typename CondT>
26     struct if_else_parser
27         : public condition_evaluator<typename as_parser<CondT>::type>
28         , public binary
29         <
30             typename as_parser<ParsableTrueT>::type,
31             typename as_parser<ParsableFalseT>::type,
32             parser< if_else_parser<ParsableTrueT, ParsableFalseT, CondT> >
33         >
34     {
35         typedef if_else_parser<ParsableTrueT, ParsableFalseT, CondT>  self_t;
36 
37         typedef as_parser<ParsableTrueT>            as_parser_true_t;
38         typedef as_parser<ParsableFalseT>           as_parser_false_t;
39         typedef typename as_parser_true_t::type     parser_true_t;
40         typedef typename as_parser_false_t::type    parser_false_t;
41         typedef as_parser<CondT>                    cond_as_parser_t;
42         typedef typename cond_as_parser_t::type     condition_t;
43 
44         typedef binary<parser_true_t, parser_false_t, parser<self_t> > base_t;
45         typedef condition_evaluator<condition_t>                       eval_t;
46 
if_else_parserboost::spirit::impl::if_else_parser47         if_else_parser
48         (
49             ParsableTrueT  const& p_true,
50             ParsableFalseT const& p_false,
51             CondT          const& cond_
52         )
53             : eval_t(cond_as_parser_t::convert(cond_))
54             , base_t
55                 (
56                     as_parser_true_t::convert(p_true),
57                     as_parser_false_t::convert(p_false)
58                 )
59         { }
60 
61         template <typename ScannerT>
62         struct result
63         {
64             typedef typename match_result<ScannerT, nil_t>::type type;
65         };
66 
67         template <typename ScannerT>
68         typename parser_result<self_t, ScannerT>::type
parseboost::spirit::impl::if_else_parser69         parse(ScannerT const& scan) const
70         {
71             typedef typename parser_result
72                 <parser_true_t, ScannerT>::type   then_result_t;
73             typedef typename parser_result
74                 <parser_false_t, ScannerT>::type  else_result_t;
75 
76             typename ScannerT::iterator_t const  save(scan.first);
77 
78             std::ptrdiff_t length = this->evaluate(scan);
79             if (length >= 0)
80             {
81                 then_result_t then_result(this->left().parse(scan));
82                 if (then_result)
83                 {
84                     length += then_result.length();
85                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
86                 }
87             }
88             else
89             {
90                 else_result_t else_result(this->right().parse(scan));
91                 if (else_result)
92                 {
93                     length = else_result.length();
94                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
95                 }
96             }
97             return scan.no_match();
98         }
99     };
100 
101     //////////////////////////////////
102     // if-else-parser generator, takes the false-parser in brackets
103     // and returns the if-else-parser.
104     template <typename ParsableTrueT, typename CondT>
105     struct if_else_parser_gen
106     {
if_else_parser_genboost::spirit::impl::if_else_parser_gen107         if_else_parser_gen(ParsableTrueT const& p_true_, CondT const& cond_)
108             : p_true(p_true_)
109             , cond(cond_) {}
110 
111         template <typename ParsableFalseT>
112         if_else_parser
113         <
114             ParsableTrueT,
115             ParsableFalseT,
116             CondT
117         >
operator []boost::spirit::impl::if_else_parser_gen118         operator[](ParsableFalseT const& p_false) const
119         {
120             return if_else_parser<ParsableTrueT, ParsableFalseT, CondT>
121                 (
122                     p_true,
123                     p_false,
124                     cond
125                 );
126         }
127 
128         ParsableTrueT const &p_true;
129         CondT const &cond;
130     };
131 
132     //////////////////////////////////
133     // if-parser, conditionally runs a parser is a functor condition is true.
134     // If the condition is fales, it fails the parse.
135     // It can optionally become an if-else-parser through the member else_p.
136     template <typename ParsableT, typename CondT>
137     struct if_parser
138         : public condition_evaluator<typename as_parser<CondT>::type>
139         , public unary
140         <
141             typename as_parser<ParsableT>::type,
142             parser<if_parser<ParsableT, CondT> > >
143     {
144         typedef if_parser<ParsableT, CondT>           self_t;
145         typedef as_parser<ParsableT>                  as_parser_t;
146         typedef typename as_parser_t::type            parser_t;
147 
148         typedef as_parser<CondT>                      cond_as_parser_t;
149         typedef typename cond_as_parser_t::type       condition_t;
150         typedef condition_evaluator<condition_t>      eval_t;
151         typedef unary<parser_t, parser<self_t> >      base_t;
152 
if_parserboost::spirit::impl::if_parser153         if_parser(ParsableT const& p, CondT const& cond_)
154             : eval_t(cond_as_parser_t::convert(cond_))
155             , base_t(as_parser_t::convert(p))
156             , else_p(p, cond_)
157         {}
158 
159         template <typename ScannerT>
160         struct result
161         {
162             typedef typename match_result<ScannerT, nil_t>::type type;
163         };
164 
165         template <typename ScannerT>
166         typename parser_result<self_t, ScannerT>::type
parseboost::spirit::impl::if_parser167         parse(ScannerT const& scan) const
168         {
169             typedef typename parser_result<parser_t, ScannerT>::type t_result_t;
170             typename ScannerT::iterator_t const save(scan.first);
171 
172             std::ptrdiff_t length = this->evaluate(scan);
173             if (length >= 0)
174             {
175                 t_result_t then_result(this->subject().parse(scan));
176                 if (then_result)
177                 {
178                     length += then_result.length();
179                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
180                 }
181                 return scan.no_match();
182             }
183             return scan.empty_match();
184         }
185 
186         if_else_parser_gen<ParsableT, CondT> else_p;
187     };
188 
189     //////////////////////////////////
190     // if-parser generator, takes the true-parser in brackets and returns the
191     // if-parser.
192     template <typename CondT>
193     struct if_parser_gen
194     {
if_parser_genboost::spirit::impl::if_parser_gen195         if_parser_gen(CondT const& cond_) : cond(cond_) {}
196 
197         template <typename ParsableT>
198         if_parser
199         <
200             ParsableT,
201             CondT
202         >
operator []boost::spirit::impl::if_parser_gen203         operator[](ParsableT const& subject) const
204         {
205             return if_parser<ParsableT, CondT>(subject, cond);
206         }
207 
208         CondT const &cond;
209     };
210 
211 } // namespace impl
212 
213 //////////////////////////////////
214 // if_p function, returns "if" parser generator
215 
216 template <typename CondT>
217 impl::if_parser_gen<CondT>
if_p(CondT const & cond)218 if_p(CondT const& cond)
219 {
220     return impl::if_parser_gen<CondT>(cond);
221 }
222 
223 }} // namespace boost::spirit
224 
225 #endif // BOOST_SPIRIT_IF_HPP
226