/*=============================================================================
    Copyright (c) 2001-2003 Daniel Nuffer
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#ifndef BOOST_SPIRIT_ESCAPE_CHAR_HPP
#define BOOST_SPIRIT_ESCAPE_CHAR_HPP

///////////////////////////////////////////////////////////////////////////////
#include <string>
#include <iterator>
#include <cctype>
#include <boost/limits.hpp>

#include <boost/spirit/debug.hpp>

#include <boost/spirit/utility/impl/escape_char.ipp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

///////////////////////////////////////////////////////////////////////////////
//
//  escape_char_action class
//
//      Links an escape char parser with a user defined semantic action.
//      The semantic action may be a function or a functor. A function
//      should be compatible with the interface:
//
//          void f(CharT ch);
//
//      A functor should have a member operator() with a compatible signature
//      as above. The matching character is passed into the function/functor.
//      This is the default class that character parsers use when dealing with
//      the construct:
//
//          p[f]
//
//      where p is a parser and f is a function or functor.
//
///////////////////////////////////////////////////////////////////////////////
template <
    typename ParserT, typename ActionT,
    unsigned long Flags, typename CharT
>
struct escape_char_action
:   public unary<ParserT,
        parser<escape_char_action<ParserT, ActionT, Flags, CharT> > >
{
    typedef escape_char_action
        <ParserT, ActionT, Flags, CharT>        self_t;
    typedef action_parser_category              parser_category_t;
    typedef unary<ParserT, parser<self_t> >     base_t;

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, CharT>::type type;
    };

    escape_char_action(ParserT const& p, ActionT const& a)
    : base_t(p), actor(a) {}

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const& scan) const
    {
        return impl::escape_char_action_parse<Flags, CharT>::
            parse(scan, *this);
    }

    ActionT const& predicate() const { return actor; }

private:

    ActionT actor;
};

///////////////////////////////////////////////////////////////////////////////
//
//  escape_char_parser class
//
//      The escape_char_parser helps in conjunction with the escape_char_action
//      template class (see above) in parsing escaped characters. There are two
//      different variants of this parser: one for parsing C style escaped
//      characters and one for parsing LEX style escaped characters.
//
//      The C style escaped character parser is generated, when the template
//      parameter 'Flags' is equal to 'c_escapes' (a constant defined in the
//      file impl/escape_char.ipp). This parser recognizes all valid C escape
//      character sequences: '\t', '\b', '\f', '\n', '\r', '\"', '\'', '\\'
//      and the numeric style escapes '\120' (octal) and '\x2f' (hexadecimal)
//      and converts these to their character equivalent, for instance the
//      sequence of a backslash and a 'b' is parsed as the character '\b'.
//      All other escaped characters are rejected by this parser.
//
//      The LEX style escaped character parser is generated, when the template
//      parameter 'Flags' is equal to 'lex_escapes' (a constant defined in the
//      file impl/escape_char.ipp). This parser recognizes all the C style
//      escaped character sequences (as described above) and additionally
//      does not reject all other escape sequences. All not mentioned escape
//      sequences are converted by the parser to the plain character, for
//      instance '\a' will be parsed as 'a'.
//
//      All not escaped characters are parsed without modification.
//
///////////////////////////////////////////////////////////////////////////////

template <unsigned long Flags, typename CharT>
struct escape_char_action_parser_gen;

template <unsigned long Flags, typename CharT = char>
struct escape_char_parser :
    public parser<escape_char_parser<Flags, CharT> > {

    // only the values c_escapes and lex_escapes are valid for Flags
    BOOST_STATIC_ASSERT(Flags == c_escapes || Flags == lex_escapes);

    typedef escape_char_parser<Flags, CharT> self_t;
    typedef
        escape_char_action_parser_gen<Flags, CharT>
        action_parser_generator_t;

    template <typename ScannerT>
    struct result {

        typedef typename match_result<ScannerT, CharT>::type type;
    };

    template <typename ActionT>
    escape_char_action<self_t, ActionT, Flags, CharT>
    operator[](ActionT const& actor) const
    {
        return escape_char_action<self_t, ActionT, Flags, CharT>(*this, actor);
    }

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const &scan) const
    {
        return impl::escape_char_parse<CharT>::parse(scan, *this);
    }
};

template <unsigned long Flags, typename CharT>
struct escape_char_action_parser_gen {

    template <typename ParserT, typename ActionT>
    static escape_char_action<ParserT, ActionT, Flags, CharT>
    generate (ParserT const &p, ActionT const &actor)
    {
        typedef
            escape_char_action<ParserT, ActionT, Flags, CharT>
            action_parser_t;
        return action_parser_t(p, actor);
    }
};

///////////////////////////////////////////////////////////////////////////////
//
//  predefined escape_char_parser objects
//
//      These objects should be used for generating correct escaped character
//      parsers.
//
///////////////////////////////////////////////////////////////////////////////
const escape_char_parser<lex_escapes> lex_escape_ch_p =
    escape_char_parser<lex_escapes>();

const escape_char_parser<c_escapes> c_escape_ch_p =
    escape_char_parser<c_escapes>();

///////////////////////////////////////////////////////////////////////////////
}} // namespace boost::spirit

#endif
