You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							447 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
	
	
							447 lines
						
					
					
						
							15 KiB
						
					
					
				| //  Copyright (c) 2001-2011 Joel de Guzman | |
| //  Copyright (c) 2001-2011 Hartmut Kaiser | |
| // | |
| //  Distributed under the Boost Software License, Version 1.0. (See accompanying | |
| //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
|  | |
| #if !defined(BOOST_SPIRIT_KARMA_RULE_MAR_05_2007_0455PM) | |
| #define BOOST_SPIRIT_KARMA_RULE_MAR_05_2007_0455PM | |
|  | |
| #if defined(_MSC_VER) | |
| #pragma once | |
| #endif | |
|  | |
| #include <boost/assert.hpp> | |
| #include <boost/config.hpp> | |
| #include <boost/function.hpp> | |
| #include <boost/mpl/vector.hpp> | |
| #include <boost/type_traits/add_const.hpp> | |
| #include <boost/type_traits/add_reference.hpp> | |
| #include <boost/type_traits/is_same.hpp> | |
|  | |
| #include <boost/fusion/include/vector.hpp> | |
| #include <boost/fusion/include/size.hpp> | |
| #include <boost/fusion/include/make_vector.hpp> | |
| #include <boost/fusion/include/cons.hpp> | |
| #include <boost/fusion/include/as_list.hpp> | |
| #include <boost/fusion/include/as_vector.hpp> | |
|  | |
| #include <boost/spirit/home/support/unused.hpp> | |
| #include <boost/spirit/home/support/argument.hpp> | |
| #include <boost/spirit/home/support/context.hpp> | |
| #include <boost/spirit/home/support/info.hpp> | |
| #include <boost/spirit/home/karma/delimit_out.hpp> | |
| #include <boost/spirit/home/karma/detail/attributes.hpp> | |
| #include <boost/spirit/home/support/nonterminal/extract_param.hpp> | |
| #include <boost/spirit/home/support/nonterminal/locals.hpp> | |
| #include <boost/spirit/home/karma/reference.hpp> | |
| #include <boost/spirit/home/karma/detail/output_iterator.hpp> | |
| #include <boost/spirit/home/karma/nonterminal/nonterminal_fwd.hpp> | |
| #include <boost/spirit/home/karma/nonterminal/detail/generator_binder.hpp> | |
| #include <boost/spirit/home/karma/nonterminal/detail/parameterized.hpp> | |
|  | |
| #if defined(BOOST_MSVC) | |
| # pragma warning(push) | |
| # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning | |
| #endif | |
|  | |
| namespace boost { namespace spirit { namespace karma | |
| { | |
|     BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _) | |
| 
 | |
|     using spirit::_pass_type; | |
|     using spirit::_val_type; | |
|     using spirit::_a_type; | |
|     using spirit::_b_type; | |
|     using spirit::_c_type; | |
|     using spirit::_d_type; | |
|     using spirit::_e_type; | |
|     using spirit::_f_type; | |
|     using spirit::_g_type; | |
|     using spirit::_h_type; | |
|     using spirit::_i_type; | |
|     using spirit::_j_type; | |
| 
 | |
| #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS | |
|  | |
|     using spirit::_pass; | |
|     using spirit::_val; | |
|     using spirit::_a; | |
|     using spirit::_b; | |
|     using spirit::_c; | |
|     using spirit::_d; | |
|     using spirit::_e; | |
|     using spirit::_f; | |
|     using spirit::_g; | |
|     using spirit::_h; | |
|     using spirit::_i; | |
|     using spirit::_j; | |
| 
 | |
| #endif | |
|  | |
|     using spirit::info; | |
|     using spirit::locals; | |
| 
 | |
|     template < | |
|         typename OutputIterator, typename T1, typename T2, typename T3 | |
|       , typename T4> | |
|     struct rule | |
|       : proto::extends< | |
|             typename proto::terminal< | |
|                 reference<rule<OutputIterator, T1, T2, T3, T4> const> | |
|             >::type | |
|           , rule<OutputIterator, T1, T2, T3, T4> | |
|         > | |
|       , generator<rule<OutputIterator, T1, T2, T3, T4> > | |
|     { | |
|         typedef mpl::int_<generator_properties::all_properties> properties; | |
| 
 | |
|         typedef OutputIterator iterator_type; | |
|         typedef rule<OutputIterator, T1, T2, T3, T4> this_type; | |
|         typedef reference<this_type const> reference_; | |
|         typedef typename proto::terminal<reference_>::type terminal; | |
|         typedef proto::extends<terminal, this_type> base_type; | |
|         typedef mpl::vector<T1, T2, T3, T4> template_params; | |
| 
 | |
|         // the output iterator is always wrapped by karma | |
|         typedef detail::output_iterator<OutputIterator, properties> | |
|             output_iterator; | |
| 
 | |
|         // locals_type is a sequence of types to be used as local variables | |
|         typedef typename | |
|             spirit::detail::extract_locals<template_params>::type | |
|         locals_type; | |
| 
 | |
|         // The delimiter-generator type | |
|         typedef typename | |
|             spirit::detail::extract_component< | |
|                 karma::domain, template_params>::type | |
|         delimiter_type; | |
| 
 | |
|         // The rule's signature | |
|         typedef typename | |
|             spirit::detail::extract_sig<template_params>::type | |
|         sig_type; | |
| 
 | |
|         // The rule's encoding type | |
|         typedef typename | |
|             spirit::detail::extract_encoding<template_params>::type | |
|         encoding_type; | |
| 
 | |
|         // This is the rule's attribute type | |
|         typedef typename | |
|             spirit::detail::attr_from_sig<sig_type>::type | |
|         attr_type; | |
|         typedef typename add_reference< | |
|             typename add_const<attr_type>::type>::type | |
|         attr_reference_type; | |
| 
 | |
|         // parameter_types is a sequence of types passed as parameters to the rule | |
|         typedef typename | |
|             spirit::detail::params_from_sig<sig_type>::type | |
|         parameter_types; | |
| 
 | |
|         static size_t const params_size = | |
|             fusion::result_of::size<parameter_types>::type::value; | |
| 
 | |
|         // the context passed to the right hand side of a rule contains | |
|         // the attribute and the parameters for this particular rule invocation | |
|         typedef context< | |
|             fusion::cons<attr_reference_type, parameter_types> | |
|           , locals_type> | |
|         context_type; | |
| 
 | |
|         typedef function< | |
|             bool(output_iterator&, context_type&, delimiter_type const&)> | |
|         function_type; | |
| 
 | |
|         typedef typename | |
|             mpl::if_< | |
|                 is_same<encoding_type, unused_type> | |
|               , unused_type | |
|               , tag::char_code<tag::encoding, encoding_type> | |
|             >::type | |
|         encoding_modifier_type; | |
| 
 | |
|         explicit rule(std::string const& name_ = "unnamed-rule") | |
|           : base_type(terminal::make(reference_(*this))) | |
|           , name_(name_) | |
|         { | |
|         } | |
| 
 | |
|         rule(rule const& rhs) | |
|           : base_type(terminal::make(reference_(*this))) | |
|           , name_(rhs.name_) | |
|           , f(rhs.f) | |
|         { | |
|         } | |
| 
 | |
|         template <typename Auto, typename Expr> | |
|         static void define(rule& lhs, Expr const& expr, mpl::false_) | |
|         { | |
|             // Report invalid expression error as early as possible. | |
|             // If you got an error_invalid_expression error message here, | |
|             // then the expression (expr) is not a valid spirit karma expression. | |
|             BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); | |
|         } | |
| 
 | |
|         template <typename Auto, typename Expr> | |
|         static void define(rule& lhs, Expr const& expr, mpl::true_) | |
|         { | |
|             lhs.f = detail::bind_generator<Auto>( | |
|                 compile<karma::domain>(expr, encoding_modifier_type())); | |
|         } | |
| 
 | |
|         template <typename Expr> | |
|         rule (Expr const& expr, std::string const& name_ = "unnamed-rule") | |
|           : base_type(terminal::make(reference_(*this))) | |
|           , name_(name_) | |
|         { | |
|             define<mpl::false_>(*this, expr, traits::matches<karma::domain, Expr>()); | |
|         } | |
| 
 | |
|         rule& operator=(rule const& rhs) | |
|         { | |
|             // The following assertion fires when you try to initialize a rule | |
|             // from an uninitialized one. Did you mean to refer to the right | |
|             // hand side rule instead of assigning from it? In this case you | |
|             // should write lhs = rhs.alias(); | |
|             BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?"); | |
| 
 | |
|             f = rhs.f; | |
|             name_ = rhs.name_; | |
|             return *this; | |
|         } | |
| 
 | |
|         std::string const& name() const | |
|         { | |
|             return name_; | |
|         } | |
| 
 | |
|         void name(std::string const& str) | |
|         { | |
|             name_ = str; | |
|         } | |
| 
 | |
|         template <typename Expr> | |
|         rule& operator=(Expr const& expr) | |
|         { | |
|             define<mpl::false_>(*this, expr, traits::matches<karma::domain, Expr>()); | |
|             return *this; | |
|         } | |
| 
 | |
| // VC7.1 has problems to resolve 'rule' without explicit template parameters | |
| #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) | |
|         // g++ 3.3 barfs if this is a member function :( | |
|         template <typename Expr> | |
|         friend rule& operator%=(rule& r, Expr const& expr) | |
|         { | |
|             define<mpl::true_>(r, expr, traits::matches<karma::domain, Expr>()); | |
|             return r; | |
|         } | |
| 
 | |
| #if defined(BOOST_NO_RVALUE_REFERENCES) | |
|         // non-const version needed to suppress proto's %= kicking in | |
|         template <typename Expr> | |
|         friend rule& operator%=(rule& r, Expr& expr) | |
|         { | |
|             return r %= static_cast<Expr const&>(expr); | |
|         } | |
| #else | |
|         // for rvalue references | |
|         template <typename Expr> | |
|         friend rule& operator%=(rule& r, Expr&& expr) | |
|         { | |
|             define<mpl::true_>(r, expr, traits::matches<karma::domain, Expr>()); | |
|             return r; | |
|         } | |
| #endif | |
|  | |
| #else | |
|         // both friend functions have to be defined out of class as VC7.1 | |
|         // will complain otherwise | |
|         template <typename OutputIterator_, typename T1_, typename T2_ | |
|           , typename T3_, typename T4_, typename Expr> | |
|         friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
|             rule<OutputIterator_, T1_, T2_, T3_, T4_>&r, Expr const& expr); | |
| 
 | |
|         // non-const version needed to suppress proto's %= kicking in | |
|         template <typename OutputIterator_, typename T1_, typename T2_ | |
|           , typename T3_, typename T4_, typename Expr> | |
|         friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
|             rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr); | |
| #endif | |
|  | |
|         template <typename Context, typename Unused> | |
|         struct attribute | |
|         { | |
|             typedef attr_type type; | |
|         }; | |
| 
 | |
|         template <typename Context, typename Delimiter, typename Attribute> | |
|         bool generate(output_iterator& sink, Context&, Delimiter const& delim | |
|           , Attribute const& attr) const | |
|         { | |
|             if (f) | |
|             { | |
|                 // Create an attribute if none is supplied. | |
|                 typedef traits::make_attribute<attr_type, Attribute> | |
|                     make_attribute; | |
|                 typedef traits::transform_attribute< | |
|                     typename make_attribute::type, attr_type, domain> | |
|                 transform; | |
| 
 | |
|                 typename transform::type attr_ = | |
|                     traits::pre_transform<domain, attr_type>( | |
|                         make_attribute::call(attr)); | |
| 
 | |
|                 // If you are seeing a compilation error here, you are probably | |
|                 // trying to use a rule or a grammar which has inherited | |
|                 // attributes, without passing values for them. | |
|                 context_type context(attr_); | |
| 
 | |
|                 // If you are seeing a compilation error here stating that the | |
|                 // third parameter can't be converted to a karma::reference | |
|                 // then you are probably trying to use a rule or a grammar with | |
|                 // an incompatible delimiter type. | |
|                 if (f(sink, context, delim)) | |
|                 { | |
|                     // do a post-delimit if this is an implied verbatim | |
|                     if (is_same<delimiter_type, unused_type>::value) | |
|                         karma::delimit_out(sink, delim); | |
| 
 | |
|                     return true; | |
|                 } | |
|             } | |
|             return false; | |
|         } | |
| 
 | |
|         template <typename Context, typename Delimiter, typename Attribute | |
|           , typename Params> | |
|         bool generate(output_iterator& sink, Context& caller_context | |
|           , Delimiter const& delim, Attribute const& attr | |
|           , Params const& params) const | |
|         { | |
|             if (f) | |
|             { | |
|                 // Create an attribute if none is supplied. | |
|                 typedef traits::make_attribute<attr_type, Attribute> | |
|                     make_attribute; | |
|                 typedef traits::transform_attribute< | |
|                     typename make_attribute::type, attr_type, domain> | |
|                 transform; | |
| 
 | |
|                 typename transform::type attr_ = | |
|                     traits::pre_transform<domain, attr_type>( | |
|                         make_attribute::call(attr)); | |
| 
 | |
|                 // If you are seeing a compilation error here, you are probably | |
|                 // trying to use a rule or a grammar which has inherited | |
|                 // attributes, passing values of incompatible types for them. | |
|                 context_type context(attr_, params, caller_context); | |
| 
 | |
|                 // If you are seeing a compilation error here stating that the | |
|                 // third parameter can't be converted to a karma::reference | |
|                 // then you are probably trying to use a rule or a grammar with | |
|                 // an incompatible delimiter type. | |
|                 if (f(sink, context, delim)) | |
|                 { | |
|                     // do a post-delimit if this is an implied verbatim | |
|                     if (is_same<delimiter_type, unused_type>::value) | |
|                         karma::delimit_out(sink, delim); | |
| 
 | |
|                     return true; | |
|                 } | |
|             } | |
|             return false; | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             return info(name_); | |
|         } | |
| 
 | |
|         reference_ alias() const | |
|         { | |
|             return reference_(*this); | |
|         } | |
| 
 | |
|         typename proto::terminal<this_type>::type copy() const | |
|         { | |
|             typename proto::terminal<this_type>::type result = {*this}; | |
|             return result; | |
|         } | |
| 
 | |
|         // bring in the operator() overloads | |
|         rule const& get_parameterized_subject() const { return *this; } | |
|         typedef rule parameterized_subject_type; | |
|         #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp> | |
|  | |
|         std::string name_; | |
|         function_type f; | |
|     }; | |
| 
 | |
| #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) | |
|     template <typename OutputIterator_, typename T1_, typename T2_ | |
|       , typename T3_, typename T4_, typename Expr> | |
|     rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
|         rule<OutputIterator_, T1_, T2_, T3_, T4_>&r, Expr const& expr) | |
|     { | |
|         // Report invalid expression error as early as possible. | |
|         // If you got an error_invalid_expression error message here, then | |
|         // the expression (expr) is not a valid spirit karma expression. | |
|         BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); | |
| 
 | |
|         typedef typename | |
|             rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type | |
|         encoding_modifier_type; | |
| 
 | |
|         r.f = detail::bind_generator<mpl::true_>( | |
|             compile<karma::domain>(expr, encoding_modifier_type())); | |
|         return r; | |
|     } | |
| 
 | |
|     // non-const version needed to suppress proto's %= kicking in | |
|     template <typename OutputIterator_, typename T1_, typename T2_ | |
|       , typename T3_, typename T4_, typename Expr> | |
|     rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( | |
|         rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr) | |
|     { | |
|         return r %= static_cast<Expr const&>(expr); | |
|     } | |
| #endif | |
| }}} | |
| 
 | |
| namespace boost { namespace spirit { namespace traits | |
| { | |
|     namespace detail | |
|     { | |
|         template <typename RuleAttribute, typename Attribute> | |
|         struct nonterminal_handles_container | |
|           : mpl::and_< | |
|                 traits::is_container<RuleAttribute> | |
|               , is_convertible<Attribute, RuleAttribute> > | |
|         {}; | |
|     } | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template < | |
|         typename IteratorA, typename IteratorB, typename Attribute | |
|       , typename Context, typename T1, typename T2, typename T3, typename T4> | |
|     struct handles_container< | |
|             karma::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context | |
|           , IteratorB> | |
|       : detail::nonterminal_handles_container< | |
|             typename attribute_of< | |
|                 karma::rule<IteratorA, T1, T2, T3, T4> | |
|               , Context, IteratorB | |
|           >::type, Attribute> | |
|     {}; | |
| }}} | |
| 
 | |
| #if defined(BOOST_MSVC) | |
| # pragma warning(pop) | |
| #endif | |
|  | |
| #endif
 | |
| 
 |