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 #ifndef BOOST_SPIRIT_QI_OPERATOR_DIFFERENCE_HPP
8 #define BOOST_SPIRIT_QI_OPERATOR_DIFFERENCE_HPP
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/meta_compiler.hpp>
16 #include <boost/spirit/home/qi/parser.hpp>
17 #include <boost/spirit/home/qi/detail/attributes.hpp>
18 #include <boost/spirit/home/support/info.hpp>
19 #include <boost/spirit/home/support/has_semantic_action.hpp>
20 #include <boost/spirit/home/support/handles_container.hpp>
21 #include <boost/fusion/include/at.hpp>
22 #include <boost/proto/operators.hpp>
23 #include <boost/proto/tags.hpp>
24 
25 namespace boost { namespace spirit
26 {
27     ///////////////////////////////////////////////////////////////////////////
28     // Enablers
29     ///////////////////////////////////////////////////////////////////////////
30     template <>
31     struct use_operator<qi::domain, proto::tag::minus> // enables -
32       : mpl::true_ {};
33 }}
34 
35 namespace boost { namespace spirit { namespace qi
36 {
37     template <typename Left, typename Right>
38     struct difference : binary_parser<difference<Left, Right> >
39     {
40         typedef Left left_type;
41         typedef Right right_type;
42 
43         template <typename Context, typename Iterator>
44         struct attribute
45         {
46             typedef typename
47                 traits::attribute_of<left_type, Context, Iterator>::type
48             type;
49         };
50 
differenceboost::spirit::qi::difference51         difference(Left const& left_, Right const& right_)
52           : left(left_), right(right_) {}
53 
54         template <typename Iterator, typename Context
55           , typename Skipper, typename Attribute>
parseboost::spirit::qi::difference56         bool parse(Iterator& first, Iterator const& last
57           , Context& context, Skipper const& skipper
58           , Attribute& attr_) const
59         {
60             // Unlike classic Spirit, with this version of difference, the rule
61             // lit("policeman") - "police" will always fail to match.
62 
63             // Spirit2 does not count the matching chars while parsing and
64             // there is no reliable and fast way to check if the LHS matches
65             // more than the RHS.
66 
67             // Try RHS first
68             Iterator start = first;
69             if (right.parse(first, last, context, skipper, unused))
70             {
71                 // RHS succeeds, we fail.
72                 first = start;
73                 return false;
74             }
75             // RHS fails, now try LHS
76             return left.parse(first, last, context, skipper, attr_);
77         }
78 
79         template <typename Context>
whatboost::spirit::qi::difference80         info what(Context& context) const
81         {
82             return info("difference",
83                 std::make_pair(left.what(context), right.what(context)));
84         }
85 
86         Left left;
87         Right right;
88     };
89 
90     ///////////////////////////////////////////////////////////////////////////
91     // Parser generators: make_xxx function (objects)
92     ///////////////////////////////////////////////////////////////////////////
93     template <typename Elements, typename Modifiers>
94     struct make_composite<proto::tag::minus, Elements, Modifiers>
95       : make_binary_composite<Elements, difference>
96     {};
97 }}}
98 
99 namespace boost { namespace spirit { namespace traits
100 {
101     ///////////////////////////////////////////////////////////////////////////
102     template <typename Left, typename Right>
103     struct has_semantic_action<qi::difference<Left, Right> >
104       : binary_has_semantic_action<Left, Right> {};
105 
106     ///////////////////////////////////////////////////////////////////////////
107     template <typename Left, typename Right, typename Attribute
108       , typename Context, typename Iterator>
109     struct handles_container<qi::difference<Left, Right>, Attribute, Context
110       , Iterator>
111       : binary_handles_container<Left, Right, Attribute, Context, Iterator> {};
112 }}}
113 
114 #endif
115