1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #if !defined(BOOST_SPIRIT_CHAR_PARSER_APR_16_2006_0906AM)
8 #define BOOST_SPIRIT_CHAR_PARSER_APR_16_2006_0906AM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/qi/domain.hpp>
15 #include <boost/spirit/home/qi/parser.hpp>
16 #include <boost/spirit/home/qi/detail/assign_to.hpp>
17 #include <boost/spirit/home/qi/meta_compiler.hpp>
18 #include <boost/spirit/home/qi/skip_over.hpp>
19 #include <boost/spirit/home/support/unused.hpp>
20 #include <boost/spirit/home/support/info.hpp>
21 #include <boost/proto/operators.hpp>
22 #include <boost/proto/tags.hpp>
23 
24 namespace boost { namespace spirit
25 {
26     ///////////////////////////////////////////////////////////////////////////
27     // Enablers
28     ///////////////////////////////////////////////////////////////////////////
29     template <>
30     struct use_operator<qi::domain, proto::tag::complement> // enables ~
31       : mpl::true_ {};
32 }}
33 
34 namespace boost { namespace spirit { namespace traits // classification
35 {
36     namespace detail
37     {
38         BOOST_MPL_HAS_XXX_TRAIT_DEF(char_parser_id)
39     }
40 
41     template <typename T>
42     struct is_char_parser : detail::has_char_parser_id<T> {};
43 }}}
44 
45 namespace boost { namespace spirit { namespace qi
46 {
47     ///////////////////////////////////////////////////////////////////////////
48     // The base char_parser
49     ///////////////////////////////////////////////////////////////////////////
50     template <typename Derived, typename Char, typename Attr = Char>
51     struct char_parser : primitive_parser<Derived>
52     {
53         typedef Char char_type;
54         struct char_parser_id;
55 
56         // if Attr is unused_type, Derived must supply its own attribute
57         // metafunction
58         template <typename Context, typename Iterator>
59         struct attribute
60         {
61             typedef Attr type;
62         };
63 
64         template <typename Iterator, typename Context, typename Skipper, typename Attribute>
parseboost::spirit::qi::char_parser65         bool parse(Iterator& first, Iterator const& last
66           , Context& context, Skipper const& skipper, Attribute& attr_) const
67         {
68             qi::skip_over(first, last, skipper);
69 
70             if (first != last && this->derived().test(*first, context))
71             {
72                 spirit::traits::assign_to(*first, attr_);
73                 ++first;
74                 return true;
75             }
76             return false;
77         }
78 
79         // Requirement: p.test(ch, context) -> bool
80         //
81         //  ch:         character being parsed
82         //  context:    enclosing rule context
83     };
84 
85     ///////////////////////////////////////////////////////////////////////////
86     // negated_char_parser handles ~cp expressions (cp is a char_parser)
87     ///////////////////////////////////////////////////////////////////////////
88     template <typename Positive>
89     struct negated_char_parser :
90         char_parser<negated_char_parser<Positive>, typename Positive::char_type>
91     {
negated_char_parserboost::spirit::qi::negated_char_parser92         negated_char_parser(Positive const& positive_)
93           : positive(positive_) {}
94 
95         template <typename CharParam, typename Context>
testboost::spirit::qi::negated_char_parser96         bool test(CharParam ch, Context& context) const
97         {
98             return !positive.test(ch, context);
99         }
100 
101         template <typename Context>
whatboost::spirit::qi::negated_char_parser102         info what(Context& context) const
103         {
104             return info("not", positive.what(context));
105         }
106 
107         Positive positive;
108     };
109 
110     ///////////////////////////////////////////////////////////////////////////
111     // Parser generators: make_xxx function (objects)
112     ///////////////////////////////////////////////////////////////////////////
113     namespace detail
114     {
115         template <typename Positive>
116         struct make_negated_char_parser
117         {
118             typedef negated_char_parser<Positive> result_type;
operator ()boost::spirit::qi::detail::make_negated_char_parser119             result_type operator()(Positive const& positive) const
120             {
121                 return result_type(positive);
122             }
123         };
124 
125         template <typename Positive>
126         struct make_negated_char_parser<negated_char_parser<Positive> >
127         {
128             typedef Positive result_type;
operator ()boost::spirit::qi::detail::make_negated_char_parser129             result_type operator()(negated_char_parser<Positive> const& ncp) const
130             {
131                 return ncp.positive;
132             }
133         };
134     }
135 
136     template <typename Elements, typename Modifiers>
137     struct make_composite<proto::tag::complement, Elements, Modifiers>
138     {
139         typedef typename
140             fusion::result_of::value_at_c<Elements, 0>::type
141         subject;
142 
143         BOOST_SPIRIT_ASSERT_MSG((
144             traits::is_char_parser<subject>::value
145         ), subject_is_not_negatable, (subject));
146 
147         typedef typename
148             detail::make_negated_char_parser<subject>::result_type
149         result_type;
150 
operator ()boost::spirit::qi::make_composite151         result_type operator()(Elements const& elements, unused_type) const
152         {
153             return detail::make_negated_char_parser<subject>()(
154                 fusion::at_c<0>(elements));
155         }
156     };
157 }}}
158 
159 #endif
160