/*============================================================================= | |
Copyright (c) 2001-2011 Joel de Guzman | |
Distributed under the Boost Software License, Version 1.0. (See accompanying | |
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
=============================================================================*/ | |
#if !defined(SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM) | |
#define SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM | |
#if defined(_MSC_VER) | |
#pragma once | |
#endif | |
#include <boost/spirit/home/qi/meta_compiler.hpp> | |
#include <boost/spirit/home/qi/parser.hpp> | |
#include <boost/spirit/home/qi/auxiliary/lazy.hpp> | |
#include <boost/spirit/home/qi/operator/kleene.hpp> | |
#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/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 | |
{ | |
/////////////////////////////////////////////////////////////////////////// | |
// Enablers | |
/////////////////////////////////////////////////////////////////////////// | |
template <> | |
struct use_directive<qi::domain, tag::repeat> // enables repeat[p] | |
: mpl::true_ {}; | |
template <typename T> | |
struct use_directive<qi::domain | |
, terminal_ex<tag::repeat // enables repeat(exact)[p] | |
, fusion::vector1<T> > | |
> : mpl::true_ {}; | |
template <typename T> | |
struct use_directive<qi::domain | |
, terminal_ex<tag::repeat // enables repeat(min, max)[p] | |
, fusion::vector2<T, T> > | |
> : mpl::true_ {}; | |
template <typename T> | |
struct use_directive<qi::domain | |
, terminal_ex<tag::repeat // enables repeat(min, inf)[p] | |
, fusion::vector2<T, inf_type> > | |
> : mpl::true_ {}; | |
template <> // enables *lazy* repeat(exact)[p] | |
struct use_lazy_directive< | |
qi::domain | |
, tag::repeat | |
, 1 // arity | |
> : mpl::true_ {}; | |
template <> // enables *lazy* repeat(min, max)[p] | |
struct use_lazy_directive< // and repeat(min, inf)[p] | |
qi::domain | |
, tag::repeat | |
, 2 // arity | |
> : mpl::true_ {}; | |
}} | |
namespace boost { namespace spirit { namespace qi | |
{ | |
using spirit::repeat; | |
using spirit::repeat_type; | |
using spirit::inf; | |
using spirit::inf_type; | |
template <typename T> | |
struct exact_iterator // handles repeat(exact)[p] | |
{ | |
exact_iterator(T const exact) | |
: exact(exact) {} | |
typedef T type; | |
T start() const { return 0; } | |
bool got_max(T i) const { return i >= exact; } | |
bool got_min(T i) const { return i >= exact; } | |
T const exact; | |
private: | |
// silence MSVC warning C4512: assignment operator could not be generated | |
exact_iterator& operator= (exact_iterator const&); | |
}; | |
template <typename T> | |
struct finite_iterator // handles repeat(min, max)[p] | |
{ | |
finite_iterator(T const min, T const max) | |
: min BOOST_PREVENT_MACRO_SUBSTITUTION (min) | |
, max BOOST_PREVENT_MACRO_SUBSTITUTION (max) {} | |
typedef T type; | |
T start() const { return 0; } | |
bool got_max(T i) const { return i >= max; } | |
bool got_min(T i) const { return i >= min; } | |
T const min; | |
T const max; | |
private: | |
// silence MSVC warning C4512: assignment operator could not be generated | |
finite_iterator& operator= (finite_iterator const&); | |
}; | |
template <typename T> | |
struct infinite_iterator // handles repeat(min, inf)[p] | |
{ | |
infinite_iterator(T const min) | |
: min BOOST_PREVENT_MACRO_SUBSTITUTION (min) {} | |
typedef T type; | |
T start() const { return 0; } | |
bool got_max(T /*i*/) const { return false; } | |
bool got_min(T i) const { return i >= min; } | |
T const min; | |
private: | |
// silence MSVC warning C4512: assignment operator could not be generated | |
infinite_iterator& operator= (infinite_iterator const&); | |
}; | |
template <typename Subject, typename LoopIter> | |
struct repeat_parser : unary_parser<repeat_parser<Subject, LoopIter> > | |
{ | |
typedef Subject subject_type; | |
template <typename Context, typename Iterator> | |
struct attribute | |
{ | |
// Build a std::vector from the subject's attribute. Note | |
// that build_std_vector may return unused_type if the | |
// subject's attribute is an unused_type. | |
typedef typename | |
traits::build_std_vector< | |
typename traits::attribute_of< | |
Subject, Context, Iterator>::type | |
>::type | |
type; | |
}; | |
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 | |
{ | |
// 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) | |
{ | |
if (!subject.parse(save, last, context, skipper, val) || | |
!traits::push_back(required_attr, val)) | |
{ | |
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) | |
{ | |
traits::push_back(attr, v); | |
} | |
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; | |
} | |
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(); | |
typename LoopIter::type i = iter.start(); | |
// 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)) | |
{ | |
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; | |
return true; | |
} | |
template <typename Context> | |
info what(Context& context) const | |
{ | |
return info("repeat", subject.what(context)); | |
} | |
Subject subject; | |
LoopIter iter; | |
private: | |
// silence MSVC warning C4512: assignment operator could not be generated | |
repeat_parser& operator= (repeat_parser const&); | |
}; | |
/////////////////////////////////////////////////////////////////////////// | |
// Parser generators: make_xxx function (objects) | |
/////////////////////////////////////////////////////////////////////////// | |
template <typename Subject, typename Modifiers> | |
struct make_directive<tag::repeat, Subject, Modifiers> | |
{ | |
typedef kleene<Subject> result_type; | |
result_type operator()(unused_type, Subject const& subject, unused_type) const | |
{ | |
return result_type(subject); | |
} | |
}; | |
template <typename T, typename Subject, typename Modifiers> | |
struct make_directive< | |
terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers> | |
{ | |
typedef exact_iterator<T> iterator_type; | |
typedef repeat_parser<Subject, iterator_type> result_type; | |
template <typename Terminal> | |
result_type operator()( | |
Terminal const& term, Subject const& subject, unused_type) const | |
{ | |
return result_type(subject, fusion::at_c<0>(term.args)); | |
} | |
}; | |
template <typename T, typename Subject, typename Modifiers> | |
struct make_directive< | |
terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers> | |
{ | |
typedef finite_iterator<T> iterator_type; | |
typedef repeat_parser<Subject, iterator_type> result_type; | |
template <typename Terminal> | |
result_type operator()( | |
Terminal const& term, Subject const& subject, unused_type) const | |
{ | |
return result_type(subject, | |
iterator_type( | |
fusion::at_c<0>(term.args) | |
, fusion::at_c<1>(term.args) | |
) | |
); | |
} | |
}; | |
template <typename T, typename Subject, typename Modifiers> | |
struct make_directive< | |
terminal_ex<tag::repeat | |
, fusion::vector2<T, inf_type> >, Subject, Modifiers> | |
{ | |
typedef infinite_iterator<T> iterator_type; | |
typedef repeat_parser<Subject, iterator_type> result_type; | |
template <typename Terminal> | |
result_type operator()( | |
Terminal const& term, Subject const& subject, unused_type) const | |
{ | |
return result_type(subject, fusion::at_c<0>(term.args)); | |
} | |
}; | |
}}} | |
namespace boost { namespace spirit { namespace traits | |
{ | |
/////////////////////////////////////////////////////////////////////////// | |
template <typename Subject, typename LoopIter> | |
struct has_semantic_action<qi::repeat_parser<Subject, LoopIter> > | |
: unary_has_semantic_action<Subject> {}; | |
/////////////////////////////////////////////////////////////////////////// | |
template <typename Subject, typename LoopIter, typename Attribute | |
, typename Context, typename Iterator> | |
struct handles_container<qi::repeat_parser<Subject, LoopIter> | |
, Attribute, Context, Iterator> | |
: mpl::true_ {}; | |
}}} | |
#endif |