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 #ifndef BOOST_SPIRIT_QI_OPERATOR_SEQUENCE_BASE_HPP 9 #define BOOST_SPIRIT_QI_OPERATOR_SEQUENCE_BASE_HPP 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