]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
63 | 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> | |
69 | 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> | |
97 | 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> | |
119 | 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> | |
128 | 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 |