2
0
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:
Hartmut Kaiser
2011-02-05 03:48:49 +00:00
parent 31ae946ef9
commit 3fc4ceb718
54 changed files with 906 additions and 456 deletions

View File

@@ -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]

View File

@@ -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)

View File

@@ -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
};

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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_ {};
}}}

View File

@@ -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_ {};
}}}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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());
}

View File

@@ -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_ {};
}}}

View File

@@ -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<

View File

@@ -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

View File

@@ -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_ {};
}}}

View File

@@ -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_ {};
}}}

View File

@@ -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

View File

@@ -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_ {};
}}}

View File

@@ -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

View File

@@ -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)

View File

@@ -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> >
{

View File

@@ -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>

View File

@@ -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

View File

@@ -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_

View File

@@ -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
///////////////////////////////////////////////////////////////////////////////

View File

@@ -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>

View File

@@ -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;
}
};

View File

@@ -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 ]
;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)));

View File

@@ -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;

View 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;
}

View File

@@ -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;

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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");
}
{

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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_));
}

View File

@@ -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();

View File

@@ -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\" )"));