Skip to content

Commit

Permalink
ForwardIterator -> ReadableIteratorConcept & ForwardTraversalConcept
Browse files Browse the repository at this point in the history
The concept of ForwardIterator is flawed because it mixed 2 sets of concepts (value access and traversal) into 1 package.

http://www.boost.org/doc/libs/1_65_1/libs/iterator/doc/new-iter-concepts.html

It requires value_type (const)& as return type when dereference is applied, which is not mandatory in spirit parsing. A return type which is convertible to value_type is good enough. ReadableIteratorConcept and ForwardTraversalConcept should be what we need for the iterator check.

For example, the iterator of the range returned by boost::adaptors::transform(std::string, func) is normally not a ForwardIterator. But it fulfills ReadableIteratorConcept and ForwardTraversalConcept and should be able to be parsed by spirit.
  • Loading branch information
wanghan02 committed Dec 7, 2017
1 parent f5179c9 commit 766cc4c
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 32 deletions.
46 changes: 25 additions & 21 deletions include/boost/spirit/home/qi/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <boost/spirit/home/support/context.hpp>
#include <boost/spirit/home/support/nonterminal/locals.hpp>
#include <boost/spirit/home/qi/detail/parse.hpp>
#include <boost/concept_check.hpp>
#include <boost/iterator/iterator_concepts.hpp>

namespace boost { namespace spirit { namespace qi
{
Expand All @@ -27,11 +27,12 @@ namespace boost { namespace spirit { namespace qi
, Iterator last
, Expr const& expr)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function, you need to supply at least a
// forward_iterator instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

return detail::parse_impl<Expr>::call(first, last, expr);
}
Expand Down Expand Up @@ -71,11 +72,12 @@ namespace boost { namespace spirit { namespace qi
, Expr const& expr
, Attr& attr)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function, you need to supply at least a
// forward_iterator instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
Expand Down Expand Up @@ -108,11 +110,12 @@ namespace boost { namespace spirit { namespace qi
, Skipper const& skipper
, BOOST_SCOPED_ENUM(skip_flag) post_skip = skip_flag::postskip)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function, you need to supply at least a
// forward_iterator instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

return detail::phrase_parse_impl<Expr>::call(
first, last, expr, skipper, post_skip);
Expand Down Expand Up @@ -142,11 +145,12 @@ namespace boost { namespace spirit { namespace qi
, BOOST_SCOPED_ENUM(skip_flag) post_skip
, Attr& attr)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function, you need to supply at least a
// forward_iterator instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

// Report invalid expression error as early as possible.
// If you got an error_invalid_expression error message here,
Expand Down
24 changes: 13 additions & 11 deletions include/boost/spirit/home/x3/core/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/concept_check.hpp>
#include <boost/iterator/iterator_concepts.hpp>

namespace boost { namespace spirit { namespace x3
{
Expand All @@ -23,11 +23,12 @@ namespace boost { namespace spirit { namespace x3
, Parser const& p
, Attribute& attr)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function. You need to supply at least a forward_iterator
// instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

// If you get an error no matching function for call to 'as_parser'
// here, then p is not a parser or there is no suitable conversion
Expand Down Expand Up @@ -101,11 +102,12 @@ namespace boost { namespace spirit { namespace x3
, Attribute& attr
, skip_flag post_skip = skip_flag::post_skip)
{
// Make sure the iterator is at least a forward_iterator. If you got a
// compilation error here, then you are using an input_iterator while
// calling this function. You need to supply at least a forward_iterator
// instead.
BOOST_CONCEPT_ASSERT((ForwardIterator<Iterator>));
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));

static_assert(!std::is_same<Skipper, unused_type>::value,
"Error! Skipper cannot be unused_type.");
Expand Down
1 change: 1 addition & 0 deletions test/qi/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ run utree1.cpp ;
run utree2.cpp ;
run utree3.cpp ;
run utree4.cpp ;
run iterator_check.cpp ;

compile pass_container3.cpp ;
compile regression_attr_with_action.cpp ;
Expand Down
52 changes: 52 additions & 0 deletions test/qi/iterator_check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*=============================================================================
Copyright (c) 2001-2017 Joel de Guzman
Copyright (c) 2017 think-cell GmbH
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 <boost/detail/lightweight_test.hpp>
#include <boost/spirit/home/qi.hpp>
#include <boost/range/adaptor/transformed.hpp>

#include <iostream>
#include <string>
#include <functional>

namespace {
char transform_func(char c) {
return c < 'a' || 'z' < c ? c : static_cast<char>(c - 'a' + 'A');
}
}

int main()
{
using boost::adaptors::transform;
using boost::spirit::qi::raw;
using boost::spirit::qi::eps;
using boost::spirit::qi::eoi;
using boost::spirit::qi::upper;
using boost::spirit::qi::repeat;
using boost::spirit::qi::parse;

std::string input = "abcde";
boost::transformed_range<char(*)(char), std::string> const rng = transform(input, transform_func);

{
std::string str;
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), +upper >> eoi, str)));
BOOST_TEST(("ABCDE"==str));
}

{
boost::iterator_range<boost::range_iterator<boost::transformed_range<char(*)(char), std::string> const>::type> str;
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), raw[+upper >> eoi], str)));
BOOST_TEST((boost::equal(std::string("ABCDE"), str)));
}

{
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), (repeat(6)[upper] | repeat(5)[upper]) >> eoi)));
}

return boost::report_errors();
}
1 change: 1 addition & 0 deletions test/x3/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ run seek.cpp ;

run x3_variant.cpp ;
run error_handler.cpp /boost//system /boost//filesystem ;
run iterator_check.cpp ;
49 changes: 49 additions & 0 deletions test/x3/iterator_check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*=============================================================================
Copyright (c) 2001-2017 Joel de Guzman
Copyright (c) 2017 think-cell GmbH
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 <boost/detail/lightweight_test.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/range/adaptor/transformed.hpp>

#include <iostream>
#include <string>
#include <functional>

int main()
{
using boost::adaptors::transform;
using boost::spirit::x3::raw;
using boost::spirit::x3::eps;
using boost::spirit::x3::eoi;
using boost::spirit::x3::upper;
using boost::spirit::x3::repeat;
using boost::spirit::x3::parse;

std::string input = "abcde";
std::function<char(char)> func = [](char c) {
return c < 'a' || 'z' < c ? c : static_cast<char>(c - 'a' + 'A');
};
auto const rng = transform(input, func);

{
std::string str;
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), +upper >> eoi, str)));
BOOST_TEST(("ABCDE"==str));
}

{
boost::iterator_range<decltype(boost::begin(rng))> str;
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), raw[+upper >> eoi], str)));
BOOST_TEST((boost::equal(std::string("ABCDE"), str)));
}

{
BOOST_TEST((parse(boost::begin(rng), boost::end(rng), (repeat(6)[upper] | repeat(5)[upper]) >> eoi)));
}

return boost::report_errors();
}

0 comments on commit 766cc4c

Please sign in to comment.