mirror of
https://github.com/boostorg/spirit.git
synced 2026-01-19 04:42:11 +00:00
Spirit: unified handling of sequences and container components for container attributes, modified hold_any to enable streaming with wchar_t, added extract_from_container CP, fixed integral generators for const data types
[SVN r68645]
This commit is contained in:
@@ -149,8 +149,8 @@
|
||||
|
||||
[heading Known Problems]
|
||||
|
||||
* Integer literals consume input on failure, which can lead to problems with
|
||||
the alternative operator:
|
||||
* Integer literals (like `int_(10)`) consume input on failure, which can lead to
|
||||
problems with the alternative operator:
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
template <typename Context, typename Unused>
|
||||
struct attribute
|
||||
{
|
||||
typedef spirit::hold_any type;
|
||||
typedef spirit::basic_hold_any<char> type;
|
||||
};
|
||||
|
||||
auto_generator(Modifiers const& modifiers)
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
typedef Transformed type;
|
||||
static Transformed pre(Exposed& val)
|
||||
{
|
||||
return Transformed(traits::extract_from<Exposed>(val, unused));
|
||||
return Transformed(traits::extract_from<Transformed>(val, unused));
|
||||
}
|
||||
// Karma only, no post() and no fail() required
|
||||
};
|
||||
|
||||
@@ -117,8 +117,109 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Attribute, typename Exposed, typename Enable>
|
||||
struct extract_from_container
|
||||
{
|
||||
typedef typename traits::container_value<Attribute const>::type
|
||||
value_type;
|
||||
typedef typename is_convertible<value_type, Exposed>::type
|
||||
is_convertible_to_value_type;
|
||||
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<
|
||||
is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
|
||||
, Exposed const&, Exposed
|
||||
>::type type;
|
||||
|
||||
// handle case where container value type is convertible to result type
|
||||
// we simply return the front element of the container
|
||||
template <typename Context, typename Pred>
|
||||
static type call(Attribute const& attr, Context& ctx, mpl::true_, Pred)
|
||||
{
|
||||
// return first element from container
|
||||
typedef typename traits::container_iterator<Attribute const>::type
|
||||
iterator_type;
|
||||
|
||||
iterator_type it = boost::begin(attr);
|
||||
type result = *it;
|
||||
++it;
|
||||
return result;
|
||||
}
|
||||
|
||||
// handle strings
|
||||
template <typename Iterator>
|
||||
static void append_to_string(Exposed& result, Iterator begin, Iterator end)
|
||||
{
|
||||
for (Iterator i = begin; i != end; ++i)
|
||||
push_back(result, *i);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static type call(Attribute const& attr, Context& ctx, mpl::false_, mpl::true_)
|
||||
{
|
||||
typedef typename char_type_of<Attribute>::type char_type;
|
||||
|
||||
Exposed result;
|
||||
append_to_string(result, traits::get_begin<char_type>(attr)
|
||||
, traits::get_end<char_type>(attr));
|
||||
return result;
|
||||
}
|
||||
|
||||
// everything else gets just passed through
|
||||
template <typename Context>
|
||||
static type call(Attribute const& attr, Context& ctx, mpl::false_, mpl::false_)
|
||||
{
|
||||
return type(attr);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static type call(Attribute const& attr, Context& ctx)
|
||||
{
|
||||
typedef typename mpl::and_<
|
||||
traits::is_string<Exposed>, traits::is_string<Attribute>
|
||||
>::type handle_strings;
|
||||
|
||||
// return first element from container
|
||||
return call(attr, ctx, is_convertible_to_value_type()
|
||||
, handle_strings());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Attribute>
|
||||
struct extract_from_container<Attribute, Attribute>
|
||||
{
|
||||
typedef Attribute const& type;
|
||||
|
||||
template <typename Context>
|
||||
static type call(Attribute const& attr, Context& ctx)
|
||||
{
|
||||
return attr;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
{
|
||||
// overload for non-container attributes
|
||||
template <typename Exposed, typename Attribute, typename Context>
|
||||
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
||||
extract_from(Attribute const& attr, Context& ctx, mpl::false_)
|
||||
{
|
||||
return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
|
||||
}
|
||||
|
||||
// overload for containers (but not for variants or optionals
|
||||
// holding containers)
|
||||
template <typename Exposed, typename Attribute, typename Context>
|
||||
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
||||
extract_from(Attribute const& attr, Context& ctx, mpl::true_)
|
||||
{
|
||||
return extract_from_container<Attribute, Exposed>::call(attr, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Exposed, typename Attribute, typename Context>
|
||||
typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
||||
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
||||
extract_from(Attribute const& attr, Context& ctx
|
||||
#if (defined(__GNUC__) && (__GNUC__ < 4)) || \
|
||||
(defined(__APPLE__) && defined(__INTEL_COMPILER))
|
||||
@@ -126,11 +227,18 @@ namespace boost { namespace spirit { namespace traits
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
|
||||
typedef typename mpl::and_<
|
||||
traits::is_container<Attribute>
|
||||
, traits::not_is_variant<Attribute>
|
||||
, traits::not_is_optional<Attribute>
|
||||
>::type is_not_wrapped_container;
|
||||
|
||||
return detail::extract_from<Exposed>(attr, ctx
|
||||
, is_not_wrapped_container());
|
||||
}
|
||||
|
||||
template <typename Exposed, typename Context>
|
||||
unused_type extract_from(unused_type, Context&)
|
||||
inline unused_type extract_from(unused_type, Context&)
|
||||
{
|
||||
return unused;
|
||||
}
|
||||
@@ -141,7 +249,13 @@ namespace boost { namespace spirit { namespace result_of
|
||||
{
|
||||
template <typename Exposed, typename Attribute>
|
||||
struct extract_from
|
||||
: traits::extract_from_attribute<Attribute, Exposed>
|
||||
: mpl::if_<
|
||||
mpl::and_<
|
||||
traits::is_container<Attribute>
|
||||
, traits::not_is_variant<Attribute>
|
||||
, traits::not_is_optional<Attribute> >
|
||||
, traits::extract_from_container<Attribute, Exposed>
|
||||
, traits::extract_from_attribute<Attribute, Exposed> >::type
|
||||
{};
|
||||
|
||||
template <typename Exposed>
|
||||
|
||||
@@ -32,18 +32,27 @@ namespace boost { namespace spirit { namespace karma { namespace detail
|
||||
// to the RHS.
|
||||
|
||||
template <typename RHS, typename LHSAttribute
|
||||
, bool IsContainer = traits::is_container<LHSAttribute>::value>
|
||||
, bool IsContainer = traits::is_container<LHSAttribute>::value
|
||||
, bool IsSequence = fusion::traits::is_sequence<LHSAttribute>::value>
|
||||
struct has_same_elements : mpl::false_ {};
|
||||
|
||||
template <typename RHS, typename LHSAttribute>
|
||||
struct has_same_elements<RHS, LHSAttribute, true>
|
||||
struct has_same_elements<RHS, LHSAttribute, true, false>
|
||||
: mpl::or_<
|
||||
is_convertible<RHS, typename LHSAttribute::value_type>
|
||||
, is_same<typename LHSAttribute::value_type, hold_any>
|
||||
, traits::is_hold_any<typename LHSAttribute::value_type>
|
||||
> {};
|
||||
|
||||
template <typename RHS, typename T>
|
||||
struct has_same_elements<RHS, optional<T>, true>
|
||||
struct has_same_elements<RHS, optional<T>, false, false>
|
||||
: has_same_elements<RHS, T> {};
|
||||
|
||||
template <typename RHS, typename T>
|
||||
struct has_same_elements<RHS, optional<T>, true, false>
|
||||
: has_same_elements<RHS, T> {};
|
||||
|
||||
template <typename RHS, typename T>
|
||||
struct has_same_elements<RHS, optional<T>, false, true>
|
||||
: has_same_elements<RHS, T> {};
|
||||
|
||||
#define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \
|
||||
@@ -54,12 +63,26 @@ namespace boost { namespace spirit { namespace karma { namespace detail
|
||||
// container (see support/container.hpp).
|
||||
template <typename RHS, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct has_same_elements<
|
||||
RHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true>
|
||||
RHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true, false>
|
||||
: mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
|
||||
, BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
|
||||
|
||||
#undef BOOST_SPIRIT_IS_CONVERTIBLE
|
||||
|
||||
// Specialization for fusion sequences, in this case we check whether the
|
||||
// lhs attribute is convertible to the types in the sequence.
|
||||
// We return false if the rhs attribute itself is a fusion sequence.
|
||||
template <typename RHS, typename LHSAttribute>
|
||||
struct has_same_elements<RHS, LHSAttribute, false, true>
|
||||
{
|
||||
typedef typename mpl::find_if<
|
||||
LHSAttribute, mpl::not_<is_convertible<RHS, mpl::_1> >
|
||||
>::type iter;
|
||||
typedef typename mpl::end<LHSAttribute>::type end;
|
||||
|
||||
typedef typename is_same<iter, end>::type type;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// This function handles the case where the attribute (Attr) given
|
||||
// to the sequence is an STL container. This is a wrapper around F.
|
||||
@@ -73,18 +96,34 @@ namespace boost { namespace spirit { namespace karma { namespace detail
|
||||
: f(f), iter(begin), end(end)
|
||||
{}
|
||||
|
||||
bool is_at_end() const
|
||||
{
|
||||
return traits::compare(iter, end);
|
||||
}
|
||||
|
||||
void next()
|
||||
{
|
||||
traits::next(iter);
|
||||
}
|
||||
|
||||
// this is for the case when the current element expects an attribute
|
||||
// which is taken from the next entry in the container
|
||||
template <typename Component>
|
||||
bool dispatch_attribute_element(Component const& component, mpl::false_) const
|
||||
{
|
||||
// get the next value to generate from container
|
||||
if (!traits::compare(iter, end) && !f(component, traits::deref(iter)))
|
||||
if (!is_at_end() && !f(component, traits::deref(iter)))
|
||||
{
|
||||
// needs to return false as long as everything is ok
|
||||
traits::next(iter);
|
||||
return false;
|
||||
}
|
||||
|
||||
// // in non-strict mode increment iterator if the underlying
|
||||
// // generator failed
|
||||
// if (!Strict::value && !is_at_end())
|
||||
// traits::next(iter);
|
||||
|
||||
// either no elements available any more or generation failed
|
||||
return true;
|
||||
}
|
||||
@@ -180,6 +219,14 @@ namespace boost { namespace spirit { namespace karma { namespace detail
|
||||
// silence MSVC warning C4512: assignment operator could not be generated
|
||||
pass_container& operator= (pass_container const&);
|
||||
};
|
||||
|
||||
// Utility function to make a pass_container
|
||||
template <typename Strict, typename F, typename Attr, typename Iterator>
|
||||
pass_container<F, Attr, Iterator, Strict>
|
||||
inline make_pass_container(F const& f, Attr& attr, Iterator b, Iterator e)
|
||||
{
|
||||
return pass_container<F, Attr, Iterator, Strict>(f, attr, b, e);
|
||||
}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -312,7 +312,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
template <typename T, typename Policies, typename Modifiers>
|
||||
struct make_primitive<
|
||||
tag::stateful_tag<Policies, tag::bool_, T>, Modifiers>
|
||||
: detail::make_bool<Modifiers, T, Policies> {};
|
||||
: detail::make_bool<Modifiers
|
||||
, typename remove_const<T>::type, Policies> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -356,7 +357,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
terminal_ex<tag::stateful_tag<Policies, tag::bool_, T>
|
||||
, fusion::vector1<A0> >
|
||||
, Modifiers>
|
||||
: detail::make_bool_direct<Modifiers, T, Policies> {};
|
||||
: detail::make_bool_direct<Modifiers
|
||||
, typename remove_const<T>::type, Policies> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
|
||||
@@ -378,7 +378,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
|
||||
template <typename T, unsigned Radix, bool force_sign, typename Modifiers>
|
||||
struct make_primitive<tag::int_generator<T, Radix, force_sign>, Modifiers>
|
||||
: detail::make_int<T, Modifiers, Radix, force_sign> {};
|
||||
: detail::make_int<typename remove_const<T>::type
|
||||
, Modifiers, Radix, force_sign> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -436,7 +437,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
struct make_primitive<
|
||||
terminal_ex<tag::int_generator<T, Radix, force_sign>
|
||||
, fusion::vector1<A0> >, Modifiers>
|
||||
: detail::make_int_direct<T, Modifiers, Radix, force_sign> {};
|
||||
: detail::make_int_direct<typename remove_const<T>::type
|
||||
, Modifiers, Radix, force_sign> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -489,7 +491,6 @@ namespace boost { namespace spirit { namespace karma
|
||||
terminal_ex<tag::lit, fusion::vector1<A0> >
|
||||
, Modifiers
|
||||
, typename enable_if<traits::is_int<A0> >::type>
|
||||
: detail::basic_int_literal<A0, Modifiers>
|
||||
{
|
||||
static bool const lower =
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
|
||||
@@ -497,7 +498,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
|
||||
|
||||
typedef literal_int_generator<
|
||||
A0
|
||||
typename remove_const<A0>::type
|
||||
, typename spirit::detail::get_encoding_with_case<
|
||||
Modifiers, unused_type, lower || upper>::type
|
||||
, typename detail::get_casetag<Modifiers, lower || upper>::type
|
||||
|
||||
@@ -322,7 +322,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
template <typename T, typename Policies, typename Modifiers>
|
||||
struct make_primitive<
|
||||
tag::stateful_tag<Policies, tag::double_, T>, Modifiers>
|
||||
: detail::make_real<T, Modifiers, Policies> {};
|
||||
: detail::make_real<typename remove_const<T>::type
|
||||
, Modifiers, Policies> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -376,7 +377,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
terminal_ex<tag::stateful_tag<Policies, tag::double_, T>
|
||||
, fusion::vector1<A0> >
|
||||
, Modifiers>
|
||||
: detail::make_real_direct<T, Modifiers, Policies> {};
|
||||
: detail::make_real_direct<typename remove_const<T>::type
|
||||
, Modifiers, Policies> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -423,7 +425,6 @@ namespace boost { namespace spirit { namespace karma
|
||||
terminal_ex<tag::lit, fusion::vector1<A0> >
|
||||
, Modifiers
|
||||
, typename enable_if<traits::is_real<A0> >::type>
|
||||
: detail::basic_real_literal<A0, Modifiers>
|
||||
{
|
||||
static bool const lower =
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
|
||||
@@ -431,7 +432,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
|
||||
|
||||
typedef literal_real_generator<
|
||||
A0, real_policies<A0>
|
||||
typename remove_const<A0>::type, real_policies<A0>
|
||||
, typename spirit::detail::get_encoding_with_case<
|
||||
Modifiers, unused_type, lower || upper>::type
|
||||
, typename detail::get_casetag<Modifiers, lower || upper>::type
|
||||
|
||||
@@ -417,7 +417,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
|
||||
template <typename T, unsigned Radix, typename Modifiers>
|
||||
struct make_primitive<tag::uint_generator<T, Radix>, Modifiers>
|
||||
: detail::make_uint<T, Modifiers, Radix> {};
|
||||
: detail::make_uint<typename remove_const<T>::type, Modifiers, Radix> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -487,7 +487,8 @@ namespace boost { namespace spirit { namespace karma
|
||||
struct make_primitive<
|
||||
terminal_ex<tag::uint_generator<T, Radix>, fusion::vector1<A0> >
|
||||
, Modifiers>
|
||||
: detail::make_uint_direct<T, Modifiers, Radix> {};
|
||||
: detail::make_uint_direct<typename remove_const<T>::type, Modifiers, Radix>
|
||||
{};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail
|
||||
@@ -542,7 +543,6 @@ namespace boost { namespace spirit { namespace karma
|
||||
terminal_ex<tag::lit, fusion::vector1<A0> >
|
||||
, Modifiers
|
||||
, typename enable_if<traits::is_uint<A0> >::type>
|
||||
: detail::basic_uint_literal<A0, Modifiers>
|
||||
{
|
||||
static bool const lower =
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
|
||||
@@ -550,7 +550,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
|
||||
|
||||
typedef literal_uint_generator<
|
||||
A0
|
||||
typename remove_const<A0>::type
|
||||
, typename spirit::detail::get_encoding_with_case<
|
||||
Modifiers, unused_type, lower || upper>::type
|
||||
, typename detail::get_casetag<Modifiers, lower || upper>::type
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
#include <boost/spirit/home/karma/generator.hpp>
|
||||
#include <boost/spirit/home/karma/meta_compiler.hpp>
|
||||
#include <boost/spirit/home/karma/detail/output_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/get_stricttag.hpp>
|
||||
#include <boost/spirit/home/karma/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/karma/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/unused.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
@@ -41,29 +44,39 @@ namespace boost { namespace spirit { namespace karma
|
||||
struct base_kleene : unary_generator<Derived>
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename OutputIterator, typename Context, typename Delimiter
|
||||
, typename Attribute>
|
||||
bool generate_subject(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Attribute const& attr) const
|
||||
// Ignore return value in relaxed mode (failing subject generators
|
||||
// are just skipped). This allows to selectively generate items in
|
||||
// the provided attribute.
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_subject(F f, Attribute const&, mpl::false_) const
|
||||
{
|
||||
// Ignore return value, failing subject generators are just
|
||||
// skipped. This allows to selectively generate items in the
|
||||
// provided attribute.
|
||||
bool r = subject.generate(sink, ctx, d, attr);
|
||||
return !Strict::value || r;
|
||||
bool r = !f(subject);
|
||||
if (!r && !f.is_at_end())
|
||||
f.next();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Context, typename Delimiter>
|
||||
bool generate_subject(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, unused_type) const
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_subject(F f, Attribute const&, mpl::true_) const
|
||||
{
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
return subject.generate(sink, ctx, d, unused);
|
||||
return !f(subject);
|
||||
}
|
||||
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
template <typename F>
|
||||
bool generate_subject(F f, unused_type, mpl::false_) const
|
||||
{
|
||||
return !f(subject);
|
||||
}
|
||||
|
||||
// template <typename F>
|
||||
// bool generate_subject(F f, unused_type, mpl::true_) const
|
||||
// {
|
||||
// return !f(subject);
|
||||
// }
|
||||
|
||||
public:
|
||||
typedef Subject subject_type;
|
||||
typedef typename subject_type::properties properties;
|
||||
@@ -87,18 +100,28 @@ namespace boost { namespace spirit { namespace karma
|
||||
bool generate(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Attribute const& attr) const
|
||||
{
|
||||
typedef detail::fail_function<
|
||||
OutputIterator, Context, Delimiter> fail_function;
|
||||
|
||||
typedef typename traits::container_iterator<
|
||||
typename add_const<Attribute>::type
|
||||
>::type iterator_type;
|
||||
typedef typename detail::make_indirect_iterator<iterator_type>::type
|
||||
indirect_iterator_type;
|
||||
typedef detail::pass_container<
|
||||
fail_function, Attribute, indirect_iterator_type, Strict>
|
||||
pass_container;
|
||||
|
||||
iterator_type it = traits::begin(attr);
|
||||
iterator_type end = traits::end(attr);
|
||||
|
||||
pass_container pass(fail_function(sink, ctx, d),
|
||||
indirect_iterator_type(it), indirect_iterator_type(end));
|
||||
|
||||
// kleene fails only if the underlying output fails
|
||||
for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end);
|
||||
traits::next(it))
|
||||
while (!pass.is_at_end())
|
||||
{
|
||||
if (!generate_subject(sink, ctx, d, traits::deref(it)))
|
||||
if (!generate_subject(pass, attr, Strict()))
|
||||
break;
|
||||
}
|
||||
return detail::sink_is_good(sink);
|
||||
@@ -170,13 +193,13 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::kleene<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::strict_kleene<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
#include <boost/spirit/home/karma/generator.hpp>
|
||||
#include <boost/spirit/home/karma/meta_compiler.hpp>
|
||||
#include <boost/spirit/home/karma/detail/output_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/get_stricttag.hpp>
|
||||
#include <boost/spirit/home/karma/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/karma/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/unused.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
@@ -41,39 +44,35 @@ namespace boost { namespace spirit { namespace karma
|
||||
private:
|
||||
// iterate over the given container until its exhausted or the embedded
|
||||
// (left) generator succeeds
|
||||
template <
|
||||
typename OutputIterator, typename Context, typename Delimiter
|
||||
, typename Iterator, typename Attribute>
|
||||
bool generate_left(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Iterator& it, Iterator& end, Attribute const&) const
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_left(F f, Attribute const&, mpl::false_) const
|
||||
{
|
||||
if (Strict::value) {
|
||||
if (!traits::compare(it, end))
|
||||
return left.generate(sink, ctx, d, traits::deref(it));
|
||||
}
|
||||
else {
|
||||
// Failing subject generators are just skipped. This allows to
|
||||
// selectively generate items in the provided attribute.
|
||||
while (!traits::compare(it, end))
|
||||
{
|
||||
if (left.generate(sink, ctx, d, traits::deref(it)))
|
||||
return true;
|
||||
traits::next(it);
|
||||
}
|
||||
// Failing subject generators are just skipped. This allows to
|
||||
// selectively generate items in the provided attribute.
|
||||
while (!f.is_at_end())
|
||||
{
|
||||
bool r = !f(left);
|
||||
if (r)
|
||||
return true;
|
||||
if (!f.is_at_end())
|
||||
f.next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename OutputIterator, typename Context, typename Delimiter
|
||||
, typename Iterator>
|
||||
bool generate_left(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Iterator&, Iterator&, unused_type) const
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_left(F f, Attribute const&, mpl::true_) const
|
||||
{
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
return left.generate(sink, ctx, d, unused);
|
||||
return !f(left);
|
||||
}
|
||||
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
template <typename F>
|
||||
bool generate_left(F f, unused_type, mpl::false_) const
|
||||
{
|
||||
return !f(left);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -106,16 +105,29 @@ namespace boost { namespace spirit { namespace karma
|
||||
bool generate(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Attribute const& attr) const
|
||||
{
|
||||
typedef detail::fail_function<
|
||||
OutputIterator, Context, Delimiter
|
||||
> fail_function;
|
||||
|
||||
typedef typename traits::container_iterator<
|
||||
typename add_const<Attribute>::type
|
||||
>::type iterator_type;
|
||||
typedef
|
||||
typename detail::make_indirect_iterator<iterator_type>::type
|
||||
indirect_iterator_type;
|
||||
typedef detail::pass_container<
|
||||
fail_function, Attribute, indirect_iterator_type, Strict>
|
||||
pass_container;
|
||||
|
||||
iterator_type it = traits::begin(attr);
|
||||
iterator_type end = traits::end(attr);
|
||||
|
||||
if (generate_left(sink, ctx, d, it, end, attr))
|
||||
pass_container pass(fail_function(sink, ctx, d),
|
||||
indirect_iterator_type(it), indirect_iterator_type(end));
|
||||
|
||||
if (generate_left(pass, attr, Strict()))
|
||||
{
|
||||
for (traits::next(it); !traits::compare(it, end); traits::next(it))
|
||||
while (!pass.is_at_end())
|
||||
{
|
||||
// wrap the given output iterator as generate_left might fail
|
||||
detail::enable_buffering<OutputIterator> buffering(sink);
|
||||
@@ -125,7 +137,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
if (!right.generate(sink, ctx, d, unused))
|
||||
return false; // shouldn't happen
|
||||
|
||||
if (!generate_left(sink, ctx, d, it, end, attr))
|
||||
if (!generate_left(pass, attr, Strict()))
|
||||
break; // return true as one item succeeded
|
||||
}
|
||||
buffering.buffer_copy();
|
||||
@@ -203,13 +215,13 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Left, typename Right, typename Attribute
|
||||
, typename Context, typename Iterator>
|
||||
struct handles_container<karma::list<Left, Right>, Attribute
|
||||
, Context, Iterator>
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
|
||||
template <typename Left, typename Right, typename Attribute
|
||||
, typename Context, typename Iterator>
|
||||
struct handles_container<karma::strict_list<Left, Right>, Attribute
|
||||
, Context, Iterator>
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::optional<Subject>, Attribute, Context
|
||||
, Iterator>
|
||||
: unary_handles_container<Subject, Attribute, Context, Iterator> {};
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,8 +14,11 @@
|
||||
#include <boost/spirit/home/karma/domain.hpp>
|
||||
#include <boost/spirit/home/karma/generator.hpp>
|
||||
#include <boost/spirit/home/karma/meta_compiler.hpp>
|
||||
#include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/output_iterator.hpp>
|
||||
#include <boost/spirit/home/karma/detail/get_stricttag.hpp>
|
||||
#include <boost/spirit/home/karma/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/karma/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/unused.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
@@ -42,36 +45,50 @@ namespace boost { namespace spirit { namespace karma
|
||||
struct base_plus : unary_generator<Derived>
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename OutputIterator, typename Context, typename Delimiter
|
||||
, typename Attribute>
|
||||
bool generate_subject(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Attribute const& attr, bool& result) const
|
||||
// Ignore return value in relaxed mode (failing subject generators
|
||||
// are just skipped). This allows to selectively generate items in
|
||||
// the provided attribute.
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_subject(F f, Attribute const& attr, bool& result, mpl::false_) const
|
||||
{
|
||||
// Ignore return value, failing subject generators are just
|
||||
// skipped. This allows to selectively generate items in the
|
||||
// provided attribute.
|
||||
if (subject.generate(sink, ctx, d, attr)) {
|
||||
bool r = !f(subject);
|
||||
if (r)
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
return !Strict::value;
|
||||
else if (!f.is_at_end())
|
||||
f.next();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Context, typename Delimiter>
|
||||
bool generate_subject(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, unused_type, bool& result) const
|
||||
template <typename F, typename Attribute>
|
||||
bool generate_subject(F f, Attribute const& attr, bool& result, mpl::true_) const
|
||||
{
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
if (subject.generate(sink, ctx, d, unused)) {
|
||||
bool r = !f(subject);
|
||||
if (r)
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return r;
|
||||
}
|
||||
|
||||
// There is no way to distinguish a failed generator from a
|
||||
// generator to be skipped. We assume the user takes responsibility
|
||||
// for ending the loop if no attribute is specified.
|
||||
template <typename F>
|
||||
bool generate_subject(F f, unused_type, bool& result, mpl::false_) const
|
||||
{
|
||||
bool r = f(subject);
|
||||
if (!r)
|
||||
result = true;
|
||||
return !r;
|
||||
}
|
||||
|
||||
// template <typename F>
|
||||
// bool generate_subject(F f, unused_type, bool& result, mpl::true_) const
|
||||
// {
|
||||
// bool r = f(subject);
|
||||
// if (!r)
|
||||
// result = true;
|
||||
// return !r;
|
||||
// }
|
||||
|
||||
public:
|
||||
typedef Subject subject_type;
|
||||
typedef typename subject_type::properties properties;
|
||||
@@ -95,9 +112,17 @@ namespace boost { namespace spirit { namespace karma
|
||||
bool generate(OutputIterator& sink, Context& ctx
|
||||
, Delimiter const& d, Attribute const& attr) const
|
||||
{
|
||||
typedef detail::fail_function<
|
||||
OutputIterator, Context, Delimiter> fail_function;
|
||||
|
||||
typedef typename traits::container_iterator<
|
||||
typename add_const<Attribute>::type
|
||||
>::type iterator_type;
|
||||
typedef typename detail::make_indirect_iterator<iterator_type>::type
|
||||
indirect_iterator_type;
|
||||
typedef detail::pass_container<
|
||||
fail_function, Attribute, indirect_iterator_type, Strict>
|
||||
pass_container;
|
||||
|
||||
iterator_type it = traits::begin(attr);
|
||||
iterator_type end = traits::end(attr);
|
||||
@@ -106,13 +131,15 @@ namespace boost { namespace spirit { namespace karma
|
||||
if (traits::compare(it, end))
|
||||
return false;
|
||||
|
||||
pass_container pass(fail_function(sink, ctx, d),
|
||||
indirect_iterator_type(it), indirect_iterator_type(end));
|
||||
|
||||
// from now on plus fails if the underlying output fails or overall
|
||||
// no subject generators succeeded
|
||||
bool result = false;
|
||||
for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end);
|
||||
traits::next(it))
|
||||
while (!pass.is_at_end())
|
||||
{
|
||||
if (!generate_subject(sink, ctx, d, traits::deref(it), result))
|
||||
if (!generate_subject(pass, attr, result, Strict()))
|
||||
break;
|
||||
}
|
||||
return result && detail::sink_is_good(sink);
|
||||
@@ -184,14 +211,14 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::plus<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
: unary_handles_container<Subject, Attribute, Context, Iterator> {};
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::strict_plus<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
: unary_handles_container<Subject, Attribute, Context, Iterator> {};
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/detail/what_function.hpp>
|
||||
#include <boost/spirit/home/karma/detail/attributes.hpp>
|
||||
#include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
|
||||
#include <boost/spirit/home/support/algorithm/any_if.hpp>
|
||||
#include <boost/spirit/home/support/unused.hpp>
|
||||
#include <boost/spirit/home/support/sequence_base_id.hpp>
|
||||
@@ -83,83 +84,11 @@ namespace boost { namespace spirit { namespace traits
|
||||
, mpl::bitor_<mpl::_2, mpl::_1>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace boost { namespace spirit { namespace karma
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// This is a wrapper for any iterator allowing to pass a reference of it
|
||||
// to the components of the sequence
|
||||
template <typename Iterator>
|
||||
class indirect_iterator
|
||||
: public boost::iterator_facade<
|
||||
indirect_iterator<Iterator>
|
||||
, typename boost::detail::iterator_traits<Iterator>::value_type
|
||||
, boost::forward_traversal_tag
|
||||
, typename boost::detail::iterator_traits<Iterator>::value_type const&>
|
||||
{
|
||||
typedef typename boost::detail::iterator_traits<Iterator>::value_type
|
||||
base_value_type;
|
||||
|
||||
typedef boost::iterator_facade<
|
||||
indirect_iterator<Iterator>, base_value_type
|
||||
, boost::forward_traversal_tag, base_value_type const&
|
||||
> base_type;
|
||||
|
||||
public:
|
||||
indirect_iterator(Iterator& iter)
|
||||
: iter_(&iter)
|
||||
{}
|
||||
indirect_iterator(indirect_iterator const& iter)
|
||||
: iter_(iter.iter_)
|
||||
{}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment()
|
||||
{
|
||||
++*iter_;
|
||||
}
|
||||
|
||||
bool equal(indirect_iterator const& other) const
|
||||
{
|
||||
return *iter_ == *other.iter_;
|
||||
}
|
||||
|
||||
typename base_type::reference dereference() const
|
||||
{
|
||||
return **iter_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator* iter_;
|
||||
};
|
||||
|
||||
template <typename Iterator>
|
||||
struct make_indirect_iterator
|
||||
{
|
||||
typedef indirect_iterator<Iterator> type;
|
||||
};
|
||||
|
||||
template <typename Iterator>
|
||||
struct make_indirect_iterator<indirect_iterator<Iterator> >
|
||||
{
|
||||
typedef indirect_iterator<Iterator> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct make_indirect_iterator<unused_type const*>
|
||||
{
|
||||
typedef unused_type const* type;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Elements, typename Strict, typename Derived>
|
||||
struct base_sequence : nary_generator<Derived>
|
||||
{
|
||||
@@ -365,14 +294,14 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Elements, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::sequence<Elements>, Attribute, Context
|
||||
, Iterator>
|
||||
: nary_handles_container<Elements, Attribute, Context, Iterator> {};
|
||||
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
|
||||
template <typename Elements, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<karma::strict_sequence<Elements>, Attribute
|
||||
, Context, Iterator>
|
||||
: nary_handles_container<Elements, Attribute, Context, Iterator> {};
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace boost { namespace spirit { namespace karma
|
||||
template <typename Context, typename Unused = unused_type>
|
||||
struct attribute
|
||||
{
|
||||
typedef spirit::hold_any type;
|
||||
typedef spirit::basic_hold_any<Char> type;
|
||||
};
|
||||
|
||||
// any_stream_generator has an attached attribute
|
||||
|
||||
@@ -227,9 +227,9 @@ namespace boost { namespace spirit { namespace traits
|
||||
namespace detail
|
||||
{
|
||||
// overload for non-container attributes
|
||||
template <typename T, typename Attribute, typename P1, typename P2>
|
||||
template <typename T, typename Attribute>
|
||||
inline void
|
||||
assign_to(T const& val, Attribute& attr, P1, P2)
|
||||
assign_to(T const& val, Attribute& attr, mpl::false_)
|
||||
{
|
||||
assign_to_attribute_from_value<Attribute, T>::call(val, attr);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
// holding containers)
|
||||
template <typename T, typename Attribute>
|
||||
inline void
|
||||
assign_to(T const& val, Attribute& attr, mpl::true_, mpl::true_)
|
||||
assign_to(T const& val, Attribute& attr, mpl::true_)
|
||||
{
|
||||
assign_to_container_from_value<Attribute, T>::call(val, attr);
|
||||
}
|
||||
@@ -248,13 +248,13 @@ namespace boost { namespace spirit { namespace traits
|
||||
inline void
|
||||
assign_to(T const& val, Attribute& attr)
|
||||
{
|
||||
typedef typename traits::is_container<Attribute>::type is_container;
|
||||
typedef typename mpl::and_<
|
||||
traits::not_is_variant<Attribute>
|
||||
traits::is_container<Attribute>
|
||||
, traits::not_is_variant<Attribute>
|
||||
, traits::not_is_optional<Attribute>
|
||||
>::type is_not_wrapped_container;
|
||||
|
||||
detail::assign_to(val, attr, is_container(), is_not_wrapped_container());
|
||||
detail::assign_to(val, attr, is_not_wrapped_container());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -26,15 +26,24 @@ namespace boost { namespace spirit { namespace qi { namespace detail
|
||||
// to the LHS.
|
||||
|
||||
template <typename LHS, typename RHSAttribute
|
||||
, bool IsContainer = traits::is_container<RHSAttribute>::value>
|
||||
, bool IsContainer = traits::is_container<RHSAttribute>::value
|
||||
, bool IsSequence = fusion::traits::is_sequence<RHSAttribute>::value>
|
||||
struct has_same_elements : mpl::false_ {};
|
||||
|
||||
template <typename LHS, typename RHSAttribute>
|
||||
struct has_same_elements<LHS, RHSAttribute, true>
|
||||
struct has_same_elements<LHS, RHSAttribute, true, false>
|
||||
: is_convertible<typename RHSAttribute::value_type, LHS> {};
|
||||
|
||||
template <typename LHS, typename T>
|
||||
struct has_same_elements<LHS, optional<T>, true>
|
||||
struct has_same_elements<LHS, optional<T>, false, false>
|
||||
: has_same_elements<LHS, T> {};
|
||||
|
||||
template <typename LHS, typename T>
|
||||
struct has_same_elements<LHS, optional<T>, true, false>
|
||||
: has_same_elements<LHS, T> {};
|
||||
|
||||
template <typename LHS, typename T>
|
||||
struct has_same_elements<LHS, optional<T>, false, true>
|
||||
: has_same_elements<LHS, T> {};
|
||||
|
||||
#define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \
|
||||
@@ -45,12 +54,28 @@ namespace boost { namespace spirit { namespace qi { namespace detail
|
||||
// container (see support/container.hpp).
|
||||
template <typename LHS, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct has_same_elements<
|
||||
LHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true>
|
||||
LHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true, false>
|
||||
: mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
|
||||
, BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
|
||||
|
||||
#undef BOOST_SPIRIT_IS_CONVERTIBLE
|
||||
|
||||
// Specialization for fusion sequences, in this case we check whether all
|
||||
// the types in the sequence are convertible to the lhs attribute.
|
||||
// We return false if the lhs attribute itself is a fusion sequence.
|
||||
template <typename LHS, typename RHSAttribute>
|
||||
struct has_same_elements<LHS, RHSAttribute, false, true>
|
||||
{
|
||||
typedef typename mpl::find_if<
|
||||
RHSAttribute, mpl::not_<is_convertible<mpl::_1, LHS> >
|
||||
>::type iter;
|
||||
typedef typename mpl::end<RHSAttribute>::type end;
|
||||
|
||||
typedef typename mpl::and_<
|
||||
mpl::not_<fusion::traits::is_sequence<LHS> >, is_same<iter, end>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// This function handles the case where the attribute (Attr) given
|
||||
// the sequence is an STL container. This is a wrapper around F.
|
||||
// The function F does the actual parsing.
|
||||
@@ -163,6 +188,9 @@ namespace boost { namespace spirit { namespace qi { namespace detail
|
||||
, iterator_type>
|
||||
> predicate;
|
||||
|
||||
// // ensure the attribute is actually a container type
|
||||
// traits::make_container(attr);
|
||||
|
||||
return dispatch_main(component, predicate());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -18,11 +19,12 @@
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
#include <boost/spirit/home/support/common_terminals.hpp>
|
||||
#include <boost/spirit/home/qi/detail/attributes.hpp>
|
||||
#include <boost/spirit/home/qi/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/qi/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/has_semantic_action.hpp>
|
||||
#include <boost/spirit/home/support/handles_container.hpp>
|
||||
#include <boost/fusion/include/at.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace spirit
|
||||
@@ -152,57 +154,26 @@ namespace boost { namespace spirit { namespace qi
|
||||
repeat_parser(Subject const& subject, LoopIter const& iter)
|
||||
: subject(subject), iter(iter) {}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename ValueType, typename Attribute
|
||||
, typename LoopVar>
|
||||
bool parse_minimal(Iterator &first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr, ValueType& val, LoopVar& i) const
|
||||
template <typename F>
|
||||
bool parse_container(F f) const
|
||||
{
|
||||
// this scope allows save and required_attr to be reclaimed
|
||||
// immediately after we're done with the required minimum
|
||||
// iteration.
|
||||
Iterator save = first;
|
||||
std::vector<ValueType> required_attr;
|
||||
for (; !iter.got_min(i); ++i)
|
||||
typename LoopIter::type i = iter.start();
|
||||
for (/**/; !iter.got_min(i); ++i)
|
||||
{
|
||||
if (!subject.parse(save, last, context, skipper, val) ||
|
||||
!traits::push_back(required_attr, val))
|
||||
{
|
||||
if (f (subject))
|
||||
return false;
|
||||
}
|
||||
|
||||
first = save;
|
||||
traits::clear(val);
|
||||
}
|
||||
|
||||
// if we got the required number of items, these are copied
|
||||
// over (appended) to the 'real' attribute
|
||||
BOOST_FOREACH(ValueType const& v, required_attr)
|
||||
// parse some more up to the maximum specified
|
||||
typename F::iterator_type save = f.f.first;
|
||||
for (/**/; !iter.got_max(i); ++i)
|
||||
{
|
||||
traits::push_back(attr, v);
|
||||
if (f (subject))
|
||||
break;
|
||||
save = f.f.first;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename LoopVar>
|
||||
bool parse_minimal(Iterator &first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, unused_type, unused_type, LoopVar& i) const
|
||||
{
|
||||
// this scope allows save and required_attr to be reclaimed
|
||||
// immediately after we're done with the required minimum
|
||||
// iteration.
|
||||
Iterator save = first;
|
||||
for (; !iter.got_min(i); ++i)
|
||||
{
|
||||
if (!subject.parse(save, last, context, skipper, unused))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
first = save;
|
||||
}
|
||||
f.f.first = save;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,35 +183,18 @@ namespace boost { namespace spirit { namespace qi
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
{
|
||||
// create a local value if Attribute is not unused_type
|
||||
typedef typename traits::container_value<Attribute>::type
|
||||
value_type;
|
||||
value_type val = value_type();
|
||||
typename LoopIter::type i = iter.start();
|
||||
typedef detail::fail_function<Iterator, Context, Skipper>
|
||||
fail_function;
|
||||
|
||||
// ensure the attribute is actually a container type
|
||||
traits::make_container(attr);
|
||||
|
||||
// parse the minimum required
|
||||
Iterator save = first;
|
||||
if (!iter.got_min(i) &&
|
||||
!parse_minimal(save, last, context, skipper, attr, val, i))
|
||||
{
|
||||
Iterator iter = first;
|
||||
fail_function f(iter, last, context, skipper);
|
||||
if (!parse_container(detail::make_pass_container(f, attr)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse some more up to the maximum specified
|
||||
for (/**/; !iter.got_max(i); ++i) {
|
||||
if (!subject.parse(save, last, context, skipper, val) ||
|
||||
!traits::push_back(attr, val))
|
||||
{
|
||||
break;
|
||||
}
|
||||
first = save;
|
||||
traits::clear(val);
|
||||
}
|
||||
|
||||
first = save;
|
||||
first = f.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -334,7 +288,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename LoopIter, typename Attribute
|
||||
, typename Context, typename Iterator>
|
||||
struct handles_container<qi::repeat_parser<Subject, LoopIter>
|
||||
, Attribute, Context, Iterator>
|
||||
, Attribute, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace boost { namespace spirit
|
||||
, terminal_ex<tag::lit, fusion::vector1<A0> >
|
||||
, typename enable_if<is_same<A0, signed short> >::type>
|
||||
: mpl::true_ {};
|
||||
|
||||
|
||||
template <typename A0> // enables short_(n)
|
||||
struct use_terminal<qi::domain
|
||||
, terminal_ex<tag::short_, fusion::vector1<A0> > >
|
||||
@@ -69,7 +69,7 @@ namespace boost { namespace spirit
|
||||
//[primitive_parsers_enable_int
|
||||
template <> // enables int_
|
||||
struct use_terminal<qi::domain, tag::int_> : mpl::true_ {};
|
||||
//]
|
||||
//]
|
||||
|
||||
template <typename A0> // enables lit(n)
|
||||
struct use_terminal<qi::domain
|
||||
@@ -84,13 +84,13 @@ namespace boost { namespace spirit
|
||||
|
||||
template <> // enables *lazy* int_(n)
|
||||
struct use_lazy_terminal<qi::domain, tag::int_, 1> : mpl::true_ {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//[primitive_parsers_enable_long
|
||||
template <> // enables long_
|
||||
struct use_terminal<qi::domain, tag::long_> : mpl::true_ {};
|
||||
//]
|
||||
|
||||
//]
|
||||
|
||||
template <typename A0> // enables lit(n)
|
||||
struct use_terminal<qi::domain
|
||||
, terminal_ex<tag::lit, fusion::vector1<A0> >
|
||||
@@ -104,7 +104,7 @@ namespace boost { namespace spirit
|
||||
|
||||
template <> // enables *lazy* long_(n)
|
||||
struct use_lazy_terminal<qi::domain, tag::long_, 1> : mpl::true_ {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
//[primitive_parsers_enable_long_long
|
||||
@@ -236,7 +236,7 @@ namespace boost { namespace spirit { namespace qi
|
||||
{
|
||||
typedef extract_int<T, Radix, MinDigits, MaxDigits> extract;
|
||||
qi::skip_over(first, last, skipper);
|
||||
|
||||
|
||||
Iterator save = first;
|
||||
T attr_;
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace boost { namespace spirit { namespace qi
|
||||
}
|
||||
};
|
||||
//]
|
||||
|
||||
|
||||
template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
|
||||
, int MaxDigits = -1>
|
||||
struct make_direct_int
|
||||
@@ -290,7 +290,7 @@ namespace boost { namespace spirit { namespace qi
|
||||
return result_type(fusion::at_c<0>(term.args));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
|
||||
, int MaxDigits = -1>
|
||||
struct make_literal_int
|
||||
@@ -302,7 +302,7 @@ namespace boost { namespace spirit { namespace qi
|
||||
return result_type(fusion::at_c<0>(term.args));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Modifiers, typename A0>
|
||||
struct make_primitive<
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -95,8 +96,8 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Elements, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<qi::expect<Elements>, Attribute, Context
|
||||
, Iterator>
|
||||
: nary_handles_container<Elements, Attribute, Context, Iterator> {};
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -15,6 +16,8 @@
|
||||
#include <boost/spirit/home/qi/parser.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
#include <boost/spirit/home/qi/detail/attributes.hpp>
|
||||
#include <boost/spirit/home/qi/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/qi/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/support/has_semantic_action.hpp>
|
||||
#include <boost/spirit/home/support/handles_container.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
@@ -33,7 +36,6 @@ namespace boost { namespace spirit
|
||||
|
||||
namespace boost { namespace spirit { namespace qi
|
||||
{
|
||||
|
||||
//[composite_parsers_kleene
|
||||
template <typename Subject>
|
||||
struct kleene : unary_parser<kleene<Subject> >
|
||||
@@ -57,28 +59,31 @@ namespace boost { namespace spirit { namespace qi
|
||||
kleene(Subject const& subject)
|
||||
: subject(subject) {}
|
||||
|
||||
template <typename F>
|
||||
bool parse_container(F f) const
|
||||
{
|
||||
while (!f (subject))
|
||||
;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
{
|
||||
// create a local value if Attribute is not unused_type
|
||||
typedef typename traits::container_value<Attribute>::type
|
||||
value_type;
|
||||
value_type val = value_type();
|
||||
|
||||
// ensure the attribute is actually a container type
|
||||
traits::make_container(attr);
|
||||
|
||||
// Repeat while subject parses ok
|
||||
Iterator save = first;
|
||||
while (subject.parse(save, last, context, skipper, val) &&
|
||||
traits::push_back(attr, val)) // push the parsed value into our attribute
|
||||
{
|
||||
first = save;
|
||||
traits::clear(val);
|
||||
}
|
||||
typedef detail::fail_function<Iterator, Context, Skipper>
|
||||
fail_function;
|
||||
|
||||
Iterator iter = first;
|
||||
fail_function f(iter, last, context, skipper);
|
||||
parse_container(detail::make_pass_container(f, attr));
|
||||
|
||||
first = f.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -120,9 +125,9 @@ namespace boost { namespace spirit { namespace traits
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
, typename Iterator>
|
||||
struct handles_container<qi::kleene<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -15,6 +16,8 @@
|
||||
#include <boost/spirit/home/qi/parser.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
#include <boost/spirit/home/qi/detail/attributes.hpp>
|
||||
#include <boost/spirit/home/qi/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/qi/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/support/has_semantic_action.hpp>
|
||||
#include <boost/spirit/home/support/handles_container.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
@@ -55,36 +58,42 @@ namespace boost { namespace spirit { namespace qi
|
||||
list(Left const& left, Right const& right)
|
||||
: left(left), right(right) {}
|
||||
|
||||
template <typename F>
|
||||
bool parse_container(F f) const
|
||||
{
|
||||
// in order to succeed we need to match at least one element
|
||||
if (f (left))
|
||||
return false;
|
||||
|
||||
typename F::iterator_type save = f.f.first;
|
||||
while (right.parse(f.f.first, f.f.last, f.f.context, f.f.skipper, unused)
|
||||
&& !f (left))
|
||||
{
|
||||
save = f.f.first;
|
||||
}
|
||||
|
||||
f.f.first = save;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
{
|
||||
// create a local value if Attribute is not unused_type
|
||||
typedef typename traits::container_value<Attribute>::type
|
||||
value_type;
|
||||
value_type val = value_type();
|
||||
typedef detail::fail_function<Iterator, Context, Skipper>
|
||||
fail_function;
|
||||
|
||||
// ensure the attribute is actually a container type
|
||||
traits::make_container(attr);
|
||||
|
||||
Iterator save = first;
|
||||
if (!left.parse(save, last, context, skipper, val) ||
|
||||
!traits::push_back(attr, val))
|
||||
{
|
||||
Iterator iter = first;
|
||||
fail_function f(iter, last, context, skipper);
|
||||
if (!parse_container(detail::make_pass_container(f, attr)))
|
||||
return false;
|
||||
}
|
||||
first = save;
|
||||
|
||||
while (right.parse(save, last, context, skipper, unused)
|
||||
&& (traits::clear(val), true)
|
||||
&& left.parse(save, last, context, skipper, val))
|
||||
{
|
||||
if (!traits::push_back(attr, val))
|
||||
break;
|
||||
first = save;
|
||||
}
|
||||
first = f.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -119,7 +128,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Left, typename Right, typename Attribute
|
||||
, typename Context, typename Iterator>
|
||||
struct handles_container<qi::list<Left, Right>, Attribute, Context
|
||||
, Iterator>
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -16,6 +17,7 @@
|
||||
#include <boost/spirit/home/support/has_semantic_action.hpp>
|
||||
#include <boost/spirit/home/support/handles_container.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
#include <boost/spirit/home/qi/parser.hpp>
|
||||
#include <boost/spirit/home/qi/meta_compiler.hpp>
|
||||
#include <boost/spirit/home/qi/detail/assign_to.hpp>
|
||||
@@ -58,9 +60,9 @@ namespace boost { namespace spirit { namespace qi
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
bool parse_impl(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
, Attribute& attr, mpl::false_) const
|
||||
{
|
||||
// create a local value if Attribute is not unused_type
|
||||
typename spirit::result_of::optional_value<Attribute>::type val;
|
||||
@@ -73,6 +75,29 @@ namespace boost { namespace spirit { namespace qi
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse_impl(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr, mpl::true_) const
|
||||
{
|
||||
subject.parse(first, last, context, skipper, attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
{
|
||||
typedef typename spirit::result_of::optional_value<Attribute>::type
|
||||
attribute_type;
|
||||
|
||||
return parse_impl(first, last, context, skipper, attr
|
||||
, traits::is_container<attribute_type>());
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
info what(Context& context) const
|
||||
{
|
||||
@@ -102,8 +127,8 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<qi::optional<Subject>, Attribute
|
||||
, Context, Iterator>
|
||||
: unary_handles_container<Subject, Attribute, Context, Iterator> {};
|
||||
, Context, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -15,6 +16,8 @@
|
||||
#include <boost/spirit/home/qi/parser.hpp>
|
||||
#include <boost/spirit/home/support/container.hpp>
|
||||
#include <boost/spirit/home/qi/detail/attributes.hpp>
|
||||
#include <boost/spirit/home/qi/detail/fail_function.hpp>
|
||||
#include <boost/spirit/home/qi/detail/pass_container.hpp>
|
||||
#include <boost/spirit/home/support/has_semantic_action.hpp>
|
||||
#include <boost/spirit/home/support/handles_container.hpp>
|
||||
#include <boost/spirit/home/support/info.hpp>
|
||||
@@ -53,37 +56,36 @@ namespace boost { namespace spirit { namespace qi
|
||||
plus(Subject const& subject)
|
||||
: subject(subject) {}
|
||||
|
||||
template <typename F>
|
||||
bool parse_container(F f) const
|
||||
{
|
||||
// in order to succeed we need to match at least one element
|
||||
if (f (subject))
|
||||
return false;
|
||||
|
||||
while (!f (subject))
|
||||
;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Iterator, typename Context
|
||||
, typename Skipper, typename Attribute>
|
||||
bool parse(Iterator& first, Iterator const& last
|
||||
, Context& context, Skipper const& skipper
|
||||
, Attribute& attr) const
|
||||
{
|
||||
// create a local value if Attribute is not unused_type
|
||||
typedef typename traits::container_value<Attribute>::type
|
||||
value_type;
|
||||
value_type val = value_type();
|
||||
typedef detail::fail_function<Iterator, Context, Skipper>
|
||||
fail_function;
|
||||
|
||||
// ensure the attribute is actually a container type
|
||||
traits::make_container(attr);
|
||||
|
||||
Iterator save = first;
|
||||
if (!subject.parse(save, last, context, skipper, val) ||
|
||||
!traits::push_back(attr, val))
|
||||
{
|
||||
Iterator iter = first;
|
||||
fail_function f(iter, last, context, skipper);
|
||||
if (!parse_container(detail::make_pass_container(f, attr)))
|
||||
return false;
|
||||
}
|
||||
first = save;
|
||||
traits::clear(val);
|
||||
|
||||
while (subject.parse(save, last, context, skipper, val))
|
||||
{
|
||||
if (!traits::push_back(attr, val))
|
||||
break;
|
||||
|
||||
first = save;
|
||||
traits::clear(val);
|
||||
}
|
||||
first = f.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Subject, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<qi::plus<Subject>, Attribute, Context
|
||||
, Iterator>
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
@@ -88,8 +89,8 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Elements, typename Attribute, typename Context
|
||||
, typename Iterator>
|
||||
struct handles_container<qi::sequence<Elements>, Attribute, Context
|
||||
, Iterator>
|
||||
: nary_handles_container<Elements, Attribute, Context, Iterator> {};
|
||||
, Iterator>
|
||||
: mpl::true_ {};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*=============================================================================
|
||||
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)
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace boost { namespace spirit { namespace qi
|
||||
using spirit::stream;
|
||||
using spirit::wstream;
|
||||
|
||||
template <typename Char = char, typename T = spirit::hold_any>
|
||||
template <typename Char = char, typename T = spirit::basic_hold_any<char> >
|
||||
struct stream_parser
|
||||
: primitive_parser<stream_parser<Char, T> >
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <ios>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace boost { namespace spirit { namespace traits
|
||||
@@ -115,7 +116,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
|
||||
template <typename Container>
|
||||
struct is_hold_any_container
|
||||
: is_same<hold_any, typename traits::container_value<Container>::type>
|
||||
: traits::is_hold_any<typename traits::container_value<Container>::type>
|
||||
{};
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
struct compute_compatible_component_variant
|
||||
: mpl::or_<
|
||||
traits::detail::attribute_is_compatible<Expected, Attribute>
|
||||
, is_same<hold_any, Expected>
|
||||
, traits::is_hold_any<Expected>
|
||||
, mpl::eval_if<
|
||||
is_container<Expected>
|
||||
, traits::detail::is_hold_any_container<Expected>
|
||||
|
||||
@@ -132,6 +132,9 @@ namespace boost { namespace spirit { namespace traits
|
||||
template <typename Attribute, typename Exposed, typename Enable = void>
|
||||
struct extract_from_attribute;
|
||||
|
||||
template <typename Attribute, typename Exposed, typename Enable = void>
|
||||
struct extract_from_container;
|
||||
|
||||
template <typename Exposed, typename Attribute, typename Context>
|
||||
typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
||||
extract_from(Attribute const& attr, Context& ctx
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
{};
|
||||
|
||||
#undef BOOST_SPIRIT_IS_CONTAINER
|
||||
|
||||
|
||||
template <typename T, typename Enable/* = void*/>
|
||||
struct is_iterator_range
|
||||
: mpl::false_
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace boost { namespace spirit
|
||||
namespace detail
|
||||
{
|
||||
// function pointer table
|
||||
template <typename Char>
|
||||
struct fxn_ptr_table
|
||||
{
|
||||
boost::detail::sp_typeinfo const& (*get_type)();
|
||||
@@ -65,18 +66,18 @@ namespace boost { namespace spirit
|
||||
void (*destruct)(void**);
|
||||
void (*clone)(void* const*, void**);
|
||||
void (*move)(void* const*, void**);
|
||||
std::istream& (*stream_in)(std::istream&, void**);
|
||||
std::ostream& (*stream_out)(std::ostream&, void* const*);
|
||||
std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**);
|
||||
std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, void* const*);
|
||||
};
|
||||
|
||||
// static functions for small value-types
|
||||
template<typename Small>
|
||||
template <typename Small>
|
||||
struct fxns;
|
||||
|
||||
template<>
|
||||
template <>
|
||||
struct fxns<mpl::true_>
|
||||
{
|
||||
template<typename T>
|
||||
template<typename T, typename Char>
|
||||
struct type
|
||||
{
|
||||
static boost::detail::sp_typeinfo const& get_type()
|
||||
@@ -101,12 +102,14 @@ namespace boost { namespace spirit
|
||||
*reinterpret_cast<T*>(dest) =
|
||||
*reinterpret_cast<T const*>(src);
|
||||
}
|
||||
static std::istream& stream_in (std::istream& i, void** obj)
|
||||
static std::basic_istream<Char>&
|
||||
stream_in (std::basic_istream<Char>& i, void** obj)
|
||||
{
|
||||
i >> *reinterpret_cast<T*>(obj);
|
||||
return i;
|
||||
}
|
||||
static std::ostream& stream_out(std::ostream& o, void* const* obj)
|
||||
static std::basic_ostream<Char>&
|
||||
stream_out(std::basic_ostream<Char>& o, void* const* obj)
|
||||
{
|
||||
o << *reinterpret_cast<T const*>(obj);
|
||||
return o;
|
||||
@@ -115,10 +118,10 @@ namespace boost { namespace spirit
|
||||
};
|
||||
|
||||
// static functions for big value-types (bigger than a void*)
|
||||
template<>
|
||||
template <>
|
||||
struct fxns<mpl::false_>
|
||||
{
|
||||
template<typename T>
|
||||
template<typename T, typename Char>
|
||||
struct type
|
||||
{
|
||||
static boost::detail::sp_typeinfo const& get_type()
|
||||
@@ -145,12 +148,14 @@ namespace boost { namespace spirit
|
||||
**reinterpret_cast<T**>(dest) =
|
||||
**reinterpret_cast<T* const*>(src);
|
||||
}
|
||||
static std::istream& stream_in(std::istream& i, void** obj)
|
||||
static std::basic_istream<Char>&
|
||||
stream_in(std::basic_istream<Char>& i, void** obj)
|
||||
{
|
||||
i >> **reinterpret_cast<T**>(obj);
|
||||
return i;
|
||||
}
|
||||
static std::ostream& stream_out(std::ostream& o, void* const* obj)
|
||||
static std::basic_ostream<Char>&
|
||||
stream_out(std::basic_ostream<Char>& o, void* const* obj)
|
||||
{
|
||||
o << **reinterpret_cast<T* const*>(obj);
|
||||
return o;
|
||||
@@ -158,22 +163,23 @@ namespace boost { namespace spirit
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct get_table
|
||||
{
|
||||
typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
|
||||
|
||||
static fxn_ptr_table* get()
|
||||
template <typename Char>
|
||||
static fxn_ptr_table<Char>* get()
|
||||
{
|
||||
static fxn_ptr_table static_table =
|
||||
static fxn_ptr_table<Char> static_table =
|
||||
{
|
||||
fxns<is_small>::template type<T>::get_type,
|
||||
fxns<is_small>::template type<T>::static_delete,
|
||||
fxns<is_small>::template type<T>::destruct,
|
||||
fxns<is_small>::template type<T>::clone,
|
||||
fxns<is_small>::template type<T>::move,
|
||||
fxns<is_small>::template type<T>::stream_in,
|
||||
fxns<is_small>::template type<T>::stream_out
|
||||
fxns<is_small>::template type<T, Char>::get_type,
|
||||
fxns<is_small>::template type<T, Char>::static_delete,
|
||||
fxns<is_small>::template type<T, Char>::destruct,
|
||||
fxns<is_small>::template type<T, Char>::clone,
|
||||
fxns<is_small>::template type<T, Char>::move,
|
||||
fxns<is_small>::template type<T, Char>::stream_in,
|
||||
fxns<is_small>::template type<T, Char>::stream_out
|
||||
};
|
||||
return &static_table;
|
||||
}
|
||||
@@ -207,13 +213,14 @@ namespace boost { namespace spirit
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
class hold_any
|
||||
template <typename Char>
|
||||
class basic_hold_any
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
template <typename T>
|
||||
explicit hold_any(T const& x)
|
||||
: table(spirit::detail::get_table<T>::get()), object(0)
|
||||
explicit basic_hold_any(T const& x)
|
||||
: table(spirit::detail::get_table<T>::template get<Char>()), object(0)
|
||||
{
|
||||
if (spirit::detail::get_table<T>::is_small::value)
|
||||
new (&object) T(x);
|
||||
@@ -221,26 +228,26 @@ namespace boost { namespace spirit
|
||||
object = new T(x);
|
||||
}
|
||||
|
||||
hold_any()
|
||||
: table(spirit::detail::get_table<spirit::detail::empty>::get()),
|
||||
basic_hold_any()
|
||||
: table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
|
||||
object(0)
|
||||
{
|
||||
}
|
||||
|
||||
hold_any(hold_any const& x)
|
||||
: table(spirit::detail::get_table<spirit::detail::empty>::get()),
|
||||
basic_hold_any(basic_hold_any const& x)
|
||||
: table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
|
||||
object(0)
|
||||
{
|
||||
assign(x);
|
||||
}
|
||||
|
||||
~hold_any()
|
||||
~basic_hold_any()
|
||||
{
|
||||
table->static_delete(&object);
|
||||
}
|
||||
|
||||
// assignment
|
||||
hold_any& assign(hold_any const& x)
|
||||
basic_hold_any& assign(basic_hold_any const& x)
|
||||
{
|
||||
if (&x != this) {
|
||||
// are we copying between the same type?
|
||||
@@ -258,11 +265,11 @@ namespace boost { namespace spirit
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
hold_any& assign(T const& x)
|
||||
basic_hold_any& assign(T const& x)
|
||||
{
|
||||
// are we copying between the same type?
|
||||
spirit::detail::fxn_ptr_table* x_table =
|
||||
spirit::detail::get_table<T>::get();
|
||||
spirit::detail::fxn_ptr_table<Char>* x_table =
|
||||
spirit::detail::get_table<T>::template get<Char>();
|
||||
if (table == x_table) {
|
||||
// if so, we can avoid deallocating and re-use memory
|
||||
table->destruct(&object); // first destruct the old content
|
||||
@@ -292,13 +299,13 @@ namespace boost { namespace spirit
|
||||
|
||||
// assignment operator
|
||||
template <typename T>
|
||||
hold_any& operator=(T const& x)
|
||||
basic_hold_any& operator=(T const& x)
|
||||
{
|
||||
return assign(x);
|
||||
}
|
||||
|
||||
// utility functions
|
||||
hold_any& swap(hold_any& x)
|
||||
basic_hold_any& swap(basic_hold_any& x)
|
||||
{
|
||||
std::swap(table, x.table);
|
||||
std::swap(object, x.object);
|
||||
@@ -330,7 +337,7 @@ namespace boost { namespace spirit
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return table == spirit::detail::get_table<spirit::detail::empty>::get();
|
||||
return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
|
||||
}
|
||||
|
||||
void reset()
|
||||
@@ -338,7 +345,7 @@ namespace boost { namespace spirit
|
||||
if (!empty())
|
||||
{
|
||||
table->static_delete(&object);
|
||||
table = spirit::detail::get_table<spirit::detail::empty>::get();
|
||||
table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
|
||||
object = 0;
|
||||
}
|
||||
}
|
||||
@@ -347,31 +354,35 @@ namespace boost { namespace spirit
|
||||
// type has a corresponding operator defined, which is completely safe
|
||||
// because spirit::hold_any is used only in contexts where these operators
|
||||
// do exist
|
||||
friend std::istream& operator>> (std::istream& i, hold_any& obj)
|
||||
template <typename Char_>
|
||||
friend inline std::basic_istream<Char_>&
|
||||
operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
|
||||
{
|
||||
return obj.table->stream_in(i, &obj.object);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& o, hold_any const& obj)
|
||||
template <typename Char_>
|
||||
friend inline std::basic_ostream<Char_>&
|
||||
operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
|
||||
{
|
||||
return obj.table->stream_out(o, &obj.object);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
private: // types
|
||||
template<typename T>
|
||||
friend T* any_cast(hold_any *);
|
||||
template <typename T, typename Char_>
|
||||
friend T* any_cast(basic_hold_any<Char_> *);
|
||||
#else
|
||||
public: // types (public so any_cast can be non-friend)
|
||||
#endif
|
||||
// fields
|
||||
spirit::detail::fxn_ptr_table* table;
|
||||
spirit::detail::fxn_ptr_table<Char>* table;
|
||||
void* object;
|
||||
};
|
||||
|
||||
// boost::any-like casting
|
||||
template <typename T>
|
||||
inline T* any_cast (hold_any* operand)
|
||||
template <typename T, typename Char>
|
||||
inline T* any_cast (basic_hold_any<Char>* operand)
|
||||
{
|
||||
if (operand && operand->type() == BOOST_SP_TYPEID(T)) {
|
||||
return spirit::detail::get_table<T>::is_small::value ?
|
||||
@@ -381,14 +392,14 @@ namespace boost { namespace spirit
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T const* any_cast(hold_any const* operand)
|
||||
template <typename T, typename Char>
|
||||
inline T const* any_cast(basic_hold_any<Char> const* operand)
|
||||
{
|
||||
return any_cast<T>(const_cast<hold_any*>(operand));
|
||||
return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T any_cast(hold_any& operand)
|
||||
template <typename T, typename Char>
|
||||
T any_cast(basic_hold_any<Char>& operand)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
|
||||
|
||||
@@ -408,8 +419,8 @@ namespace boost { namespace spirit
|
||||
return *result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T const& any_cast(hold_any const& operand)
|
||||
template <typename T, typename Char>
|
||||
T const& any_cast(basic_hold_any<Char> const& operand)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
|
||||
|
||||
@@ -419,10 +430,23 @@ namespace boost { namespace spirit
|
||||
BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
|
||||
#endif
|
||||
|
||||
return any_cast<nonref const&>(const_cast<hold_any &>(operand));
|
||||
return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// backwards compatibility
|
||||
typedef basic_hold_any<char> hold_any;
|
||||
typedef basic_hold_any<wchar_t> whold_any;
|
||||
|
||||
namespace traits
|
||||
{
|
||||
template <typename T>
|
||||
struct is_hold_any : mpl::false_ {};
|
||||
|
||||
template <typename Char>
|
||||
struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}} // namespace boost::spirit
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
#include <ios>
|
||||
#include <boost/spirit/home/support/utree/utree.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost { namespace spirit { namespace qi
|
||||
{
|
||||
template <typename Subject> struct kleene;
|
||||
}}}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace boost { namespace spirit { namespace traits
|
||||
{
|
||||
@@ -59,6 +64,11 @@ namespace boost { namespace spirit { namespace traits
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_uninitialized(utree const& ut)
|
||||
{
|
||||
return traits::which(ut) == utree_type::invalid_type;
|
||||
}
|
||||
}
|
||||
|
||||
// this specialization tells Spirit how to extract the type of the value
|
||||
@@ -507,8 +517,15 @@ namespace boost { namespace spirit { namespace traits
|
||||
{
|
||||
static void call(utree& ut)
|
||||
{
|
||||
if (!detail::is_list(ut))
|
||||
ut = empty_list;
|
||||
if (!detail::is_list(ut)) {
|
||||
if (detail::is_uninitialized(ut))
|
||||
ut = empty_list;
|
||||
else {
|
||||
utree retval (empty_list);
|
||||
retval.push_back(ut);
|
||||
ut.swap(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -644,7 +661,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
// only 'invalid_type' utree nodes are not valid
|
||||
static bool is_valid(utree const& val)
|
||||
{
|
||||
return traits::which(val) != utree_type::invalid_type;
|
||||
return !detail::is_uninitialized(val);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -943,7 +960,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
}
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, utree::nil_type>
|
||||
struct extract_from_container<utree, utree::nil_type>
|
||||
{
|
||||
typedef utree::nil_type type;
|
||||
|
||||
@@ -955,7 +972,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, char>
|
||||
struct extract_from_container<utree, char>
|
||||
{
|
||||
typedef char type;
|
||||
|
||||
@@ -968,7 +985,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, bool>
|
||||
struct extract_from_container<utree, bool>
|
||||
{
|
||||
typedef bool type;
|
||||
|
||||
@@ -980,7 +997,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, int>
|
||||
struct extract_from_container<utree, int>
|
||||
{
|
||||
typedef int type;
|
||||
|
||||
@@ -992,7 +1009,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, double>
|
||||
struct extract_from_container<utree, double>
|
||||
{
|
||||
typedef double type;
|
||||
|
||||
@@ -1004,7 +1021,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <typename Traits, typename Alloc>
|
||||
struct extract_from_attribute<utree, std::basic_string<char, Traits, Alloc> >
|
||||
struct extract_from_container<utree, std::basic_string<char, Traits, Alloc> >
|
||||
{
|
||||
typedef std::basic_string<char, Traits, Alloc> type;
|
||||
|
||||
@@ -1017,7 +1034,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, utf8_symbol_type>
|
||||
struct extract_from_container<utree, utf8_symbol_type>
|
||||
{
|
||||
typedef std::string type;
|
||||
|
||||
@@ -1030,7 +1047,7 @@ namespace boost { namespace spirit { namespace traits
|
||||
};
|
||||
|
||||
template <>
|
||||
struct extract_from_attribute<utree, utf8_string_type>
|
||||
struct extract_from_container<utree, utf8_string_type>
|
||||
{
|
||||
typedef std::string type;
|
||||
|
||||
@@ -1123,7 +1140,10 @@ namespace boost { namespace spirit { namespace traits
|
||||
static type pre(iterator_range<Iterator> const& t)
|
||||
{
|
||||
// return utree the begin iterator points to
|
||||
return utree(boost::ref(t.front()));
|
||||
Iterator it = boost::begin(t);
|
||||
utree result(boost::ref(*it));
|
||||
++it;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -194,6 +194,7 @@ import testing ;
|
||||
[ run karma/regression_optional_double.cpp : : : : karma_regression_optional_double ]
|
||||
[ run karma/regression_semantic_action_attribute.cpp : : : : karma_regression_semantic_action_attribute ]
|
||||
[ run karma/regression_real_scientific.cpp : : : : karma_regression_real_scientific ]
|
||||
[ compile karma/regression_const_real_policies.cpp : : regression_const_real_policies ]
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <boost/spirit/include/phoenix_statement.hpp>
|
||||
#include <boost/fusion/include/std_pair.hpp>
|
||||
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
using namespace spirit_test;
|
||||
@@ -62,6 +64,57 @@ int main()
|
||||
BOOST_TEST(test_delimited("", *char_, s2, ' '));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1("aaaaa");
|
||||
BOOST_TEST(test("aaaaa", char_ << *(char_ << char_), s1));
|
||||
BOOST_TEST(test_delimited("a a a a a ",
|
||||
char_ << *(char_ << char_), s1, ' '));
|
||||
|
||||
s1 = "a";
|
||||
BOOST_TEST(test("a", char_ << *(char_ << char_), s1));
|
||||
s1 = "aa";
|
||||
BOOST_TEST(!test("", char_ << *(char_ << char_), s1));
|
||||
// BOOST_TEST(test("aa", char_ << *buffer[char_ << char_] << char_, s1));
|
||||
s1 = "aaaa";
|
||||
BOOST_TEST(!test("", char_ << *(char_ << char_), s1));
|
||||
// BOOST_TEST(test("aaaa", char_ << *buffer[char_ << char_] << char_, s1));
|
||||
}
|
||||
|
||||
{
|
||||
using boost::spirit::karma::strict;
|
||||
using boost::spirit::karma::relaxed;
|
||||
using namespace boost::assign;
|
||||
|
||||
typedef std::pair<char, char> data;
|
||||
std::vector<data> v1;
|
||||
v1 += std::make_pair('a', 'a'),
|
||||
std::make_pair('b', 'b'),
|
||||
std::make_pair('c', 'c'),
|
||||
std::make_pair('d', 'd'),
|
||||
std::make_pair('e', 'e'),
|
||||
std::make_pair('f', 'f'),
|
||||
std::make_pair('g', 'g');
|
||||
|
||||
karma::rule<spirit_test::output_iterator<char>::type, data()> r;
|
||||
r = &char_('a') << char_;
|
||||
|
||||
BOOST_TEST(test("a", r << *(r << r), v1));
|
||||
BOOST_TEST(test("a", relaxed[r << *(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << *(r << r)], v1));
|
||||
|
||||
v1 += std::make_pair('a', 'a');
|
||||
|
||||
BOOST_TEST(!test("", r << *(r << r), v1));
|
||||
BOOST_TEST(!test("", relaxed[r << *(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << *(r << r)], v1));
|
||||
|
||||
v1 += std::make_pair('a', 'a');
|
||||
|
||||
BOOST_TEST(test("aaa", r << *(r << r), v1));
|
||||
BOOST_TEST(test("aaa", relaxed[r << *(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << *(r << r)], v1));
|
||||
}
|
||||
|
||||
{
|
||||
using namespace boost::assign;
|
||||
|
||||
|
||||
@@ -75,6 +75,13 @@ int main()
|
||||
char_ % ',', s, space));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s ("abcdefg");
|
||||
BOOST_TEST(test("abc,de,fg", char_ << ((char_ << char_) % ','), s));
|
||||
BOOST_TEST(test_delimited("a b c , d e , f g ",
|
||||
char_ << ((char_ << char_) % ','), s, space));
|
||||
}
|
||||
|
||||
{ // actions
|
||||
namespace phx = boost::phoenix;
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ main()
|
||||
|
||||
BOOST_TEST(test("abc", str));
|
||||
BOOST_TEST(!test("abcd", str));
|
||||
}
|
||||
|
||||
{
|
||||
using namespace boost::spirit::standard_wide;
|
||||
|
||||
std::basic_string<wchar_t> wstr(L"abc");
|
||||
BOOST_TEST(test(L"abc", lit(wstr)));
|
||||
|
||||
@@ -66,6 +66,55 @@ int main()
|
||||
BOOST_TEST(!test_delimited("", +char_, s3, ' '));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1("aaaaa");
|
||||
BOOST_TEST(test("aaaaa", char_ << +(char_ << char_), s1));
|
||||
BOOST_TEST(test_delimited("a a a a a ",
|
||||
char_ << +(char_ << char_), s1, ' '));
|
||||
|
||||
s1 = "a";
|
||||
BOOST_TEST(!test("", char_ << +(char_ << char_), s1));
|
||||
s1 = "aa";
|
||||
BOOST_TEST(!test("", char_ << +(char_ << char_), s1));
|
||||
s1 = "aaaa";
|
||||
BOOST_TEST(!test("", char_ << +(char_ << char_), s1));
|
||||
}
|
||||
|
||||
{
|
||||
using boost::spirit::karma::strict;
|
||||
using boost::spirit::karma::relaxed;
|
||||
using namespace boost::assign;
|
||||
|
||||
typedef std::pair<char, char> data;
|
||||
std::vector<data> v1;
|
||||
v1 += std::make_pair('a', 'a'),
|
||||
std::make_pair('b', 'b'),
|
||||
std::make_pair('c', 'c'),
|
||||
std::make_pair('d', 'd'),
|
||||
std::make_pair('e', 'e'),
|
||||
std::make_pair('f', 'f'),
|
||||
std::make_pair('g', 'g');
|
||||
|
||||
karma::rule<spirit_test::output_iterator<char>::type, data()> r;
|
||||
r = &char_('a') << char_;
|
||||
|
||||
BOOST_TEST(!test("", r << +(r << r), v1));
|
||||
BOOST_TEST(!test("", relaxed[r << +(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << +(r << r)], v1));
|
||||
|
||||
v1 += std::make_pair('a', 'a');
|
||||
|
||||
BOOST_TEST(!test("", r << *(r << r), v1));
|
||||
BOOST_TEST(!test("", relaxed[r << +(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << +(r << r)], v1));
|
||||
|
||||
v1 += std::make_pair('a', 'a');
|
||||
|
||||
BOOST_TEST(test("aaa", r << +(r << r), v1));
|
||||
BOOST_TEST(test("aaa", relaxed[r << +(r << r)], v1));
|
||||
BOOST_TEST(!test("", strict[r << +(r << r)], v1));
|
||||
}
|
||||
|
||||
{
|
||||
using namespace boost::assign;
|
||||
|
||||
|
||||
25
test/karma/regression_const_real_policies.cpp
Normal file
25
test/karma/regression_const_real_policies.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2001-2011 Hartmut Kaiser
|
||||
// Copyright (c) 2011 Jeroen Habraken
|
||||
//
|
||||
// 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)
|
||||
|
||||
// compile test verifying it's possible to use const types for real_policies.
|
||||
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::spirit::karma;
|
||||
|
||||
typedef real_generator<double const, real_policies<double const> >
|
||||
double_const_type;
|
||||
|
||||
std::string generated;
|
||||
generate(std::back_inserter(generated), double_const_type(), 1.0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -49,6 +49,15 @@ int main()
|
||||
BOOST_TEST(test_delimited("A B C D E F G H ", upper[repeat(8)[char_]], str, space));
|
||||
}
|
||||
|
||||
// {
|
||||
// std::string s1 = "aaaaa";
|
||||
// BOOST_TEST(test("aaaaa", char_ << repeat(2)[char_ << char_], s1));
|
||||
// s1 = "aaa";
|
||||
// BOOST_TEST(test("aaa", char_ << repeat(1, 2)[char_ << char_], s1));
|
||||
// s1 = "aa";
|
||||
// BOOST_TEST(!test("", char_ << repeat(1)[char_ << char_], s1));
|
||||
// }
|
||||
|
||||
{ // actions
|
||||
namespace phx = boost::phoenix;
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// 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)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cwchar>
|
||||
#include <streambuf>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include <boost/spirit/include/karma_char.hpp>
|
||||
#include <boost/spirit/include/karma_string.hpp>
|
||||
|
||||
@@ -62,8 +62,8 @@ int main()
|
||||
rule<output_iterator, utree::const_range()> r1list;
|
||||
|
||||
r1 = double_ | int_ | r1str | r1list | r1ref;
|
||||
|
||||
r1ref = r1;
|
||||
|
||||
r1ref = r1.alias();
|
||||
|
||||
r1str = string;
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// 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)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cwchar>
|
||||
#include <streambuf>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include <boost/spirit/include/karma_char.hpp>
|
||||
#include <boost/spirit/include/karma_string.hpp>
|
||||
|
||||
@@ -216,6 +216,14 @@ main()
|
||||
BOOST_TEST(s == "abc");
|
||||
}
|
||||
|
||||
{
|
||||
using boost::spirit::qi::int_;
|
||||
|
||||
int i = 0;
|
||||
BOOST_TEST( (test_attr("10", int_(5) | int_(10), i)) );
|
||||
BOOST_TEST(i == 10);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ main()
|
||||
BOOST_TEST(test(" a a a a b a b a b a a a b b a ", start, space, false));
|
||||
}
|
||||
|
||||
{ // std::contaner attributes
|
||||
{ // std::container attributes
|
||||
|
||||
typedef boost::fusion::vector<int, char> fs;
|
||||
rule<char const*, std::vector<fs>(), space_type> start;
|
||||
|
||||
@@ -87,16 +87,10 @@ main()
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b ", *char_, s, space) && s == "bbbb");
|
||||
|
||||
// The following 4 tests show that omit does not inhibit explicit attributes
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("bbbb", *omit[char_('b')], s) && s == "bbbb");
|
||||
|
||||
// The following 2 tests show that omit does not inhibit explicit attributes
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("bbbb", omit[*char_('b')], s) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b", *omit[char_('b')], s, space) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b", omit[*char_('b')], s, space) && s == "bbbb");
|
||||
}
|
||||
|
||||
@@ -49,6 +49,21 @@ main()
|
||||
std::string s;
|
||||
BOOST_TEST(test_attr("a,b,c,d,e,f,g,h", char_ % ',', s));
|
||||
BOOST_TEST(s == "abcdefgh");
|
||||
|
||||
BOOST_TEST(!test("a,b,c,d,e,f,g,h,", char_ % ','));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s;
|
||||
BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> char_) % ',', s));
|
||||
BOOST_TEST(s == "abcdefgh");
|
||||
|
||||
BOOST_TEST(!test("ab,cd,ef,gh,", (char_ >> char_) % ','));
|
||||
BOOST_TEST(!test("ab,cd,ef,g", (char_ >> char_) % ','));
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("ab,cd,efg", (char_ >> char_) % ',' >> char_, s));
|
||||
BOOST_TEST(s == "abcdefg");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -80,6 +80,12 @@ main()
|
||||
BOOST_TEST((n.get() == 1234));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s;
|
||||
BOOST_TEST((test_attr("abc", char_ >> -(char_ >> char_), s)));
|
||||
BOOST_TEST(s == "abc");
|
||||
}
|
||||
|
||||
{
|
||||
namespace phx = boost::phoenix;
|
||||
|
||||
|
||||
@@ -94,17 +94,11 @@ main()
|
||||
}
|
||||
|
||||
{
|
||||
// The following 4 tests show that omit does not inhibit explicit attributes
|
||||
// The following 2 tests show that omit does not inhibit explicit attributes
|
||||
|
||||
std::string s;
|
||||
BOOST_TEST(test_attr("bbbb", +omit[char_('b')], s) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("bbbb", omit[+char_('b')], s) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b ", +omit[char_('b')], s, space) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b ", omit[+char_('b')], s, space) && s == "bbbb");
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ int main()
|
||||
omit[-qi::char_(" \t")];
|
||||
strrule_type correct_year = repeat(4)[qi::digit];
|
||||
|
||||
test("1776", correct_year | repeat(2)[qi::digit], "1776");
|
||||
test("1776", qi::hold[correct_year] | repeat(2)[qi::digit], "1776");
|
||||
test("76", obsolete_year, "76");
|
||||
test("76", obsolete_year | correct_year, "76");
|
||||
test(" 76", correct_year | obsolete_year, "76");
|
||||
test("76", correct_year | obsolete_year, "76");
|
||||
test("76", correct_year | repeat(2)[qi::digit], "76");
|
||||
test("76", qi::hold[obsolete_year] | correct_year, "76");
|
||||
test(" 76", qi::hold[correct_year] | obsolete_year, "76");
|
||||
test("76", qi::hold[correct_year] | obsolete_year, "76");
|
||||
test("76", qi::hold[correct_year] | repeat(2)[qi::digit], "76");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -77,6 +77,40 @@ main()
|
||||
BOOST_TEST(!test("aa", repeat(3, inf)[char_]));
|
||||
}
|
||||
|
||||
{
|
||||
std::string s;
|
||||
BOOST_TEST(test_attr("aaaaaaaa", repeat[char_ >> char_], s)); // kleene synonym
|
||||
BOOST_TEST(s == "aaaaaaaa");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("aaaaaaaa", repeat(4)[char_ >> char_], s));
|
||||
BOOST_TEST(s == "aaaaaaaa");
|
||||
|
||||
BOOST_TEST(!test("aa", repeat(3)[char_ >> char_]));
|
||||
BOOST_TEST(!test("a", repeat(1)[char_ >> char_]));
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("aa", repeat(1, 3)[char_ >> char_], s));
|
||||
BOOST_TEST(s == "aa");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("aaaaaa", repeat(1, 3)[char_ >> char_], s));
|
||||
BOOST_TEST(s == "aaaaaa");
|
||||
|
||||
BOOST_TEST(!test("aaaaaaa", repeat(1, 3)[char_ >> char_]));
|
||||
BOOST_TEST(!test("a", repeat(1, 3)[char_ >> char_]));
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("aaaa", repeat(2, inf)[char_ >> char_], s));
|
||||
BOOST_TEST(s == "aaaa");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("aaaaaa", repeat(2, inf)[char_ >> char_], s));
|
||||
BOOST_TEST(s == "aaaaaa");
|
||||
|
||||
BOOST_TEST(!test("aa", repeat(2, inf)[char_ >> char_]));
|
||||
}
|
||||
|
||||
{ // from classic spirit tests
|
||||
BOOST_TEST(test("", repeat(0, inf)['x']));
|
||||
|
||||
@@ -142,16 +176,10 @@ main()
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b", repeat(4)[char_], s, space) && s == "bbbb");
|
||||
|
||||
// The following 4 tests show that omit does not inhibit explicit attributes
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("bbbb", repeat(4)[omit[char_('b')]], s) && s == "bbbb");
|
||||
|
||||
// The following 2 tests show that omit does not inhibit explicit attributes
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("bbbb", omit[repeat(4)[char_('b')]], s) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b", repeat(4)[omit[char_('b')]], s, space) && s == "bbbb");
|
||||
|
||||
s.clear();
|
||||
BOOST_TEST(test_attr("b b b b", omit[repeat(4)[char_('b')]], s, space) && s == "bbbb");
|
||||
}
|
||||
@@ -166,9 +194,7 @@ main()
|
||||
BOOST_TEST(test_attr("1 2 3", int_ >> repeat(2)[int_], v, space));
|
||||
BOOST_TEST(v.size() == 3 && v[0] == 1 && v[1] == 2 && v[2] == 3);
|
||||
|
||||
v.clear();
|
||||
BOOST_TEST(!test_attr("1 2", int_ >> repeat(2)[int_], v, space));
|
||||
BOOST_TEST(v.size() == 1 && v[0] == 1);
|
||||
BOOST_TEST(!test("1 2", int_ >> repeat(2)[int_], space));
|
||||
}
|
||||
|
||||
{ // actions
|
||||
|
||||
@@ -172,6 +172,38 @@ main()
|
||||
BOOST_TEST(v[2] == 'c');
|
||||
}
|
||||
|
||||
{ // alternative forms of attributes. Allow sequences to take in
|
||||
// stl containers.
|
||||
using boost::spirit::qi::hold;
|
||||
|
||||
std::vector<char> v;
|
||||
BOOST_TEST(test_attr("abc", char_ >> *(char_ >> char_), v));
|
||||
BOOST_TEST(v.size() == 3);
|
||||
BOOST_TEST(v[0] == 'a');
|
||||
BOOST_TEST(v[1] == 'b');
|
||||
BOOST_TEST(v[2] == 'c');
|
||||
|
||||
v.clear();
|
||||
BOOST_TEST(!test_attr("abcd", char_ >> *(char_ >> char_), v));
|
||||
|
||||
v.clear();
|
||||
BOOST_TEST(test_attr("abcdef", char_ >> *hold[char_ >> char_] >> char_, v));
|
||||
BOOST_TEST(v.size() == 6);
|
||||
BOOST_TEST(v[0] == 'a');
|
||||
BOOST_TEST(v[1] == 'b');
|
||||
BOOST_TEST(v[2] == 'c');
|
||||
BOOST_TEST(v[3] == 'd');
|
||||
BOOST_TEST(v[4] == 'e');
|
||||
BOOST_TEST(v[5] == 'f');
|
||||
|
||||
v.clear();
|
||||
BOOST_TEST(test_attr("abc", char_ >> +(char_ >> char_), v));
|
||||
BOOST_TEST(v.size() == 3);
|
||||
BOOST_TEST(v[0] == 'a');
|
||||
BOOST_TEST(v[1] == 'b');
|
||||
BOOST_TEST(v[2] == 'c');
|
||||
}
|
||||
|
||||
{ // alternative forms of attributes. Allow sequences to take in
|
||||
// stl containers.
|
||||
|
||||
@@ -248,7 +280,6 @@ main()
|
||||
}
|
||||
|
||||
{ // testing "what"
|
||||
|
||||
print_info(what(alpha | char_('x') >> lit("hello") >> int_));
|
||||
}
|
||||
|
||||
|
||||
@@ -165,26 +165,22 @@ int main()
|
||||
|
||||
BOOST_TEST(test_attr("a25.5b", r1 > r2 >> r3, ut));
|
||||
BOOST_TEST(ut.which() == utree_type::list_type);
|
||||
BOOST_TEST(check(ut, "( \"a\" ( ( 25.5 ) ( \"b\" ) ) )"));
|
||||
// FIXME: "( \"a\" ( 25.5 ) ( \"b\" ) )"
|
||||
BOOST_TEST(check(ut, "( \"a\" ( 25.5 ) ( \"b\" ) )"));
|
||||
ut.clear();
|
||||
|
||||
BOOST_TEST(test_attr("a25.5b", r3 >> r2 > r1, ut));
|
||||
BOOST_TEST(ut.which() == utree_type::list_type);
|
||||
BOOST_TEST(check(ut, "( ( ( \"a\" ) ( 25.5 ) ) \"b\" )"));
|
||||
// FIXME: "( ( \"a\" ) ( 25.5 ) \"b\" )"
|
||||
BOOST_TEST(check(ut, "( ( \"a\" ) ( 25.5 ) \"b\" )"));
|
||||
ut.clear();
|
||||
|
||||
BOOST_TEST(test_attr("a25.5b", char_ > r2 >> r3, ut));
|
||||
BOOST_TEST(ut.which() == utree_type::list_type);
|
||||
BOOST_TEST(check(ut, "( \"a\" ( ( 25.5 ) ( \"b\" ) ) )"));
|
||||
// FIXME: "( \"a\" ( 25.5 ) ( \"b\" ) )"
|
||||
BOOST_TEST(check(ut, "( \"a\" ( 25.5 ) ( \"b\" ) )"));
|
||||
ut.clear();
|
||||
|
||||
BOOST_TEST(test_attr("a25.5b", r3 >> r2 > char_, ut));
|
||||
BOOST_TEST(ut.which() == utree_type::list_type);
|
||||
BOOST_TEST(check(ut, "( ( ( \"a\" ) ( 25.5 ) ) \"b\" )"));
|
||||
// FIXME: "( ( \"a\" ) ( 25.5 ) \"b\" )"
|
||||
BOOST_TEST(check(ut, "( ( \"a\" ) ( 25.5 ) \"b\" )"));
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
|
||||
@@ -86,8 +86,9 @@ int main()
|
||||
ut.which() == utree_type::list_type && check(ut, "( 1.23 4.56 )"));
|
||||
ut.clear();
|
||||
|
||||
rule<char const*, utree(), space_type> r1 =
|
||||
strict_double | int_ | ~char_("()") | ('(' >> *r1 >> ')');
|
||||
rule<char const*, utree(), space_type> r1;
|
||||
rule<char const*, utree::list_type(), space_type> r2 = '(' >> *r1 >> ')';
|
||||
r1 = strict_double | int_ | ~char_("()") | r2;
|
||||
|
||||
BOOST_TEST(test_attr("(x y)", r1, ut, space) &&
|
||||
ut.which() == utree_type::list_type && check(ut, "( \"x\" \"y\" )"));
|
||||
|
||||
Reference in New Issue
Block a user