1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #if !defined(SPIRIT_SEQUENCE_BASE_APRIL_22_2006_0811AM)
9 #define SPIRIT_SEQUENCE_BASE_APRIL_22_2006_0811AM
10 
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14 
15 #include <boost/spirit/home/qi/domain.hpp>
16 #include <boost/spirit/home/qi/detail/pass_container.hpp>
17 #include <boost/spirit/home/qi/detail/attributes.hpp>
18 #include <boost/spirit/home/support/algorithm/any_if.hpp>
19 #include <boost/spirit/home/support/detail/what_function.hpp>
20 #include <boost/spirit/home/support/unused.hpp>
21 #include <boost/spirit/home/support/info.hpp>
22 #include <boost/spirit/home/support/sequence_base_id.hpp>
23 #include <boost/spirit/home/support/has_semantic_action.hpp>
24 #include <boost/spirit/home/qi/parser.hpp>
25 #include <boost/fusion/include/as_vector.hpp>
26 #include <boost/fusion/include/vector.hpp>
27 #include <boost/fusion/include/for_each.hpp>
28 #include <boost/mpl/identity.hpp>
29 
30 namespace boost { namespace spirit { namespace qi
31 {
32     template <typename Derived, typename Elements>
33     struct sequence_base // this class is shared by sequence and expect
34       : nary_parser<Derived>
35     {
36         typedef Elements elements_type;
37         struct sequence_base_id;
38 
39         template <typename Context, typename Iterator>
40         struct attribute
41         {
42             // Put all the element attributes in a tuple
43             typedef typename traits::build_attribute_sequence<
44                 Elements, Context, traits::sequence_attribute_transform
45               , Iterator, qi::domain
46             >::type all_attributes;
47 
48             // Now, build a fusion vector over the attributes. Note
49             // that build_fusion_vector 1) removes all unused attributes
50             // and 2) may return unused_type if all elements have
51             // unused_type(s).
52             typedef typename
53                 traits::build_fusion_vector<all_attributes>::type
54             type_;
55 
56             // Finally, strip single element vectors into its
57             // naked form: vector1<T> --> T
58             typedef typename
59                 traits::strip_single_element_vector<type_>::type
60             type;
61         };
62 
sequence_baseboost::spirit::qi::sequence_base63         sequence_base(Elements const& elements_)
64           : elements(elements_) {}
65 
66         // standard case. Attribute is a fusion tuple
67         template <typename Iterator, typename Context
68           , typename Skipper, typename Attribute>
parse_implboost::spirit::qi::sequence_base69         bool parse_impl(Iterator& first, Iterator const& last
70           , Context& context, Skipper const& skipper
71           , Attribute& attr_, mpl::false_) const
72         {
73             Iterator iter = first;
74             typedef traits::attribute_not_unused<Context, Iterator> predicate;
75 
76             // wrap the attribute in a tuple if it is not a tuple or if the
77             // attribute of this sequence is a single element tuple
78             typedef typename attribute<Context, Iterator>::type_ attr_type_;
79             typename traits::wrap_if_not_tuple<Attribute
80               , typename mpl::and_<
81                     traits::one_element_sequence<attr_type_>
82                   , mpl::not_<traits::one_element_sequence<Attribute> >
83                 >::type
84             >::type attr_local(attr_);
85 
86             // return false if *any* of the parsers fail
87             if (spirit::any_if(elements, attr_local
88               , Derived::fail_function(iter, last, context, skipper), predicate()))
89                 return false;
90             first = iter;
91             return true;
92         }
93 
94         // Special case when Attribute is an stl container
95         template <typename Iterator, typename Context
96           , typename Skipper, typename Attribute>
parse_implboost::spirit::qi::sequence_base97         bool parse_impl(Iterator& first, Iterator const& last
98           , Context& context, Skipper const& skipper
99           , Attribute& attr_, mpl::true_) const
100         {
101             // ensure the attribute is actually a container type
102             traits::make_container(attr_);
103 
104             Iterator iter = first;
105             // return false if *any* of the parsers fail
106             if (fusion::any(elements
107               , detail::make_sequence_pass_container(
108                     Derived::fail_function(iter, last, context, skipper), attr_))
109                 )
110                 return false;
111             first = iter;
112             return true;
113         }
114 
115         // main parse function. Dispatches to parse_impl depending
116         // on the Attribute type.
117         template <typename Iterator, typename Context
118           , typename Skipper, typename Attribute>
parseboost::spirit::qi::sequence_base119         bool parse(Iterator& first, Iterator const& last
120           , Context& context, Skipper const& skipper
121           , Attribute& attr_) const
122         {
123             return parse_impl(first, last, context, skipper, attr_
124               , traits::is_container<Attribute>());
125         }
126 
127         template <typename Context>
whatboost::spirit::qi::sequence_base128         info what(Context& context) const
129         {
130             info result(this->derived().id());
131             fusion::for_each(elements,
132                 spirit::detail::what_function<Context>(result, context));
133             return result;
134         }
135 
136         Elements elements;
137     };
138 }}}
139 
140 #endif
141