sl@0: /*=============================================================================
sl@0:     Copyright (c) 2002-2003 Joel de Guzman
sl@0:     Copyright (c) 2002 Juan Carlos Arevalo-Baeza
sl@0:     Copyright (c) 2002-2003 Martin Wille
sl@0:     http://spirit.sourceforge.net/
sl@0: 
sl@0:     Use, modification and distribution is subject to the Boost Software
sl@0:     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
sl@0:     http://www.boost.org/LICENSE_1_0.txt)
sl@0: =============================================================================*/
sl@0: #ifndef BOOST_SPIRIT_IF_HPP
sl@0: #define BOOST_SPIRIT_IF_HPP
sl@0: 
sl@0: #include <boost/spirit/core/parser.hpp>
sl@0: #include <boost/spirit/core/composite/composite.hpp>
sl@0: #include <boost/spirit/dynamic/impl/conditions.ipp>
sl@0: 
sl@0: namespace boost { namespace spirit {
sl@0: 
sl@0:     namespace impl {
sl@0: 
sl@0:     //////////////////////////////////
sl@0:     // if-else-parser, holds two alternative parsers and a conditional functor
sl@0:     // that selects between them.
sl@0:     template <typename ParsableTrueT, typename ParsableFalseT, typename CondT>
sl@0:     struct if_else_parser
sl@0:         : public condition_evaluator<typename as_parser<CondT>::type>
sl@0:         , public binary
sl@0:         <
sl@0:             typename as_parser<ParsableTrueT>::type,
sl@0:             typename as_parser<ParsableFalseT>::type,
sl@0:             parser< if_else_parser<ParsableTrueT, ParsableFalseT, CondT> >
sl@0:         >
sl@0:     {
sl@0:         typedef if_else_parser<ParsableTrueT, ParsableFalseT, CondT>  self_t;
sl@0: 
sl@0:         typedef as_parser<ParsableTrueT>            as_parser_true_t;
sl@0:         typedef as_parser<ParsableFalseT>           as_parser_false_t;
sl@0:         typedef typename as_parser_true_t::type     parser_true_t;
sl@0:         typedef typename as_parser_false_t::type    parser_false_t;
sl@0:         typedef as_parser<CondT>                    cond_as_parser_t;
sl@0:         typedef typename cond_as_parser_t::type     condition_t;
sl@0: 
sl@0:         typedef binary<parser_true_t, parser_false_t, parser<self_t> > base_t;
sl@0:         typedef condition_evaluator<condition_t>                       eval_t;
sl@0: 
sl@0:         if_else_parser
sl@0:         (
sl@0:             ParsableTrueT  const& p_true,
sl@0:             ParsableFalseT const& p_false,
sl@0:             CondT          const& cond_
sl@0:         )
sl@0:             : eval_t(cond_as_parser_t::convert(cond_))
sl@0:             , base_t
sl@0:                 (
sl@0:                     as_parser_true_t::convert(p_true),
sl@0:                     as_parser_false_t::convert(p_false)
sl@0:                 )
sl@0:         { }
sl@0: 
sl@0:         template <typename ScannerT>
sl@0:         struct result
sl@0:         {
sl@0:             typedef typename match_result<ScannerT, nil_t>::type type;
sl@0:         };
sl@0: 
sl@0:         template <typename ScannerT>
sl@0:         typename parser_result<self_t, ScannerT>::type
sl@0:         parse(ScannerT const& scan) const
sl@0:         {
sl@0:             typedef typename parser_result
sl@0:                 <parser_true_t, ScannerT>::type   then_result_t;
sl@0:             typedef typename parser_result
sl@0:                 <parser_false_t, ScannerT>::type  else_result_t;
sl@0: 
sl@0:             typename ScannerT::iterator_t const  save(scan.first);
sl@0: 
sl@0:             std::ptrdiff_t length = this->evaluate(scan);
sl@0:             if (length >= 0)
sl@0:             {
sl@0:                 then_result_t then_result(this->left().parse(scan));
sl@0:                 if (then_result)
sl@0:                 {
sl@0:                     length += then_result.length();
sl@0:                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
sl@0:                 }
sl@0:             }
sl@0:             else
sl@0:             {
sl@0:                 else_result_t else_result(this->right().parse(scan));
sl@0:                 if (else_result)
sl@0:                 {
sl@0:                     length = else_result.length();
sl@0:                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
sl@0:                 }
sl@0:             }
sl@0:             return scan.no_match();
sl@0:         }
sl@0:     };
sl@0: 
sl@0:     //////////////////////////////////
sl@0:     // if-else-parser generator, takes the false-parser in brackets
sl@0:     // and returns the if-else-parser.
sl@0:     template <typename ParsableTrueT, typename CondT>
sl@0:     struct if_else_parser_gen
sl@0:     {
sl@0:         if_else_parser_gen(ParsableTrueT const& p_true_, CondT const& cond_)
sl@0:             : p_true(p_true_)
sl@0:             , cond(cond_) {}
sl@0: 
sl@0:         template <typename ParsableFalseT>
sl@0:         if_else_parser
sl@0:         <
sl@0:             ParsableTrueT,
sl@0:             ParsableFalseT,
sl@0:             CondT
sl@0:         >
sl@0:         operator[](ParsableFalseT const& p_false) const
sl@0:         {
sl@0:             return if_else_parser<ParsableTrueT, ParsableFalseT, CondT>
sl@0:                 (
sl@0:                     p_true,
sl@0:                     p_false,
sl@0:                     cond
sl@0:                 );
sl@0:         }
sl@0: 
sl@0:         ParsableTrueT const &p_true;
sl@0:         CondT const &cond;
sl@0:     };
sl@0: 
sl@0:     //////////////////////////////////
sl@0:     // if-parser, conditionally runs a parser is a functor condition is true.
sl@0:     // If the condition is fales, it fails the parse.
sl@0:     // It can optionally become an if-else-parser through the member else_p.
sl@0:     template <typename ParsableT, typename CondT>
sl@0:     struct if_parser
sl@0:         : public condition_evaluator<typename as_parser<CondT>::type>
sl@0:         , public unary
sl@0:         <
sl@0:             typename as_parser<ParsableT>::type,
sl@0:             parser<if_parser<ParsableT, CondT> > >
sl@0:     {
sl@0:         typedef if_parser<ParsableT, CondT>           self_t;
sl@0:         typedef as_parser<ParsableT>                  as_parser_t;
sl@0:         typedef typename as_parser_t::type            parser_t;
sl@0: 
sl@0:         typedef as_parser<CondT>                      cond_as_parser_t;
sl@0:         typedef typename cond_as_parser_t::type       condition_t;
sl@0:         typedef condition_evaluator<condition_t>      eval_t;
sl@0:         typedef unary<parser_t, parser<self_t> >      base_t;
sl@0: 
sl@0:         if_parser(ParsableT const& p, CondT const& cond_)
sl@0:             : eval_t(cond_as_parser_t::convert(cond_))
sl@0:             , base_t(as_parser_t::convert(p))
sl@0:             , else_p(p, cond_)
sl@0:         {}
sl@0: 
sl@0:         template <typename ScannerT>
sl@0:         struct result
sl@0:         {
sl@0:             typedef typename match_result<ScannerT, nil_t>::type type;
sl@0:         };
sl@0: 
sl@0:         template <typename ScannerT>
sl@0:         typename parser_result<self_t, ScannerT>::type
sl@0:         parse(ScannerT const& scan) const
sl@0:         {
sl@0:             typedef typename parser_result<parser_t, ScannerT>::type t_result_t;
sl@0:             typename ScannerT::iterator_t const save(scan.first);
sl@0: 
sl@0:             std::ptrdiff_t length = this->evaluate(scan);
sl@0:             if (length >= 0)
sl@0:             {
sl@0:                 t_result_t then_result(this->subject().parse(scan));
sl@0:                 if (then_result)
sl@0:                 {
sl@0:                     length += then_result.length();
sl@0:                     return scan.create_match(std::size_t(length), nil_t(), save, scan.first);
sl@0:                 }
sl@0:                 return scan.no_match();
sl@0:             }
sl@0:             return scan.empty_match();
sl@0:         }
sl@0: 
sl@0:         if_else_parser_gen<ParsableT, CondT> else_p;
sl@0:     };
sl@0: 
sl@0:     //////////////////////////////////
sl@0:     // if-parser generator, takes the true-parser in brackets and returns the
sl@0:     // if-parser.
sl@0:     template <typename CondT>
sl@0:     struct if_parser_gen
sl@0:     {
sl@0:         if_parser_gen(CondT const& cond_) : cond(cond_) {}
sl@0: 
sl@0:         template <typename ParsableT>
sl@0:         if_parser
sl@0:         <
sl@0:             ParsableT,
sl@0:             CondT
sl@0:         >
sl@0:         operator[](ParsableT const& subject) const
sl@0:         {
sl@0:             return if_parser<ParsableT, CondT>(subject, cond);
sl@0:         }
sl@0: 
sl@0:         CondT const &cond;
sl@0:     };
sl@0: 
sl@0: } // namespace impl
sl@0: 
sl@0: //////////////////////////////////
sl@0: // if_p function, returns "if" parser generator
sl@0: 
sl@0: template <typename CondT>
sl@0: impl::if_parser_gen<CondT>
sl@0: if_p(CondT const& cond)
sl@0: {
sl@0:     return impl::if_parser_gen<CondT>(cond);
sl@0: }
sl@0: 
sl@0: }} // namespace boost::spirit
sl@0: 
sl@0: #endif // BOOST_SPIRIT_IF_HPP