boostorg / spirit

Boost.org spirit module
http://boost.org/libs/spirit
390 stars 160 forks source link

Qi: Attributeless parsers within container handling parsers #394

Open Kojoley opened 6 years ago

Kojoley commented 6 years ago

Update: https://svn.boost.org/trac10/ticket/6444 looks like the same problem.

X3 appends a default constructed value to containers if underlying parser of container handling parser (such as kleene, plus or list) does not generate anything.

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/qi.hpp>
#include <vector>
#include <iostream>

template <typename F>
void test(F f)
{
    std::vector<int> v;
    char s[] = "1\n2\n3\n---\n5\n---\n---\n7\n---";
    f(std::begin(s), std::end(s), v);
    for (auto x : v) std::cout << x << '\n';
}

int main()
{
    namespace qi = boost::spirit::qi;
    namespace x3 = boost::spirit::x3;
    std::cout << "qi:\n"; test([](auto f, auto l, auto& v){ qi::parse(f, l, (qi::int_ | "---") % qi::eol, v); });
    std::cout << "x3:\n"; test([](auto f, auto l, auto& v){ x3::parse(f, l, (x3::int_ | "---") % x3::eol, v); });
}

Output:

qi:
1
2
3
5
7
x3:
1
2
3
0
5
0
0
7
0
Kojoley commented 6 years ago

Oh god, there is inconsistency even in Qi itself.

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/qi.hpp>
#include <boost/fusion/include/std_tuple.hpp>
#include <vector>
#include <iostream>

template <typename F>
void test(F f)
{
    std::vector<std::tuple<int, char>> v;
    char s[] = "1:a\n2:b\n3:c\n---\n5:e\n---\n---\n7:h\n---";
    f(std::begin(s), std::end(s), v);
    for (auto [x, y] : v) std::cout << x << ':' << y << '\n';
}

int main()
{
    namespace qi = boost::spirit::qi;
    namespace x3 = boost::spirit::x3;
    std::cout << "qi:\n"; test([](auto f, auto l, auto& v) { qi::parse(f, l, (qi::int_ >> ':' >> qi::char_ | "---") % qi::eol, v); });
    std::cout << "x3:\n"; test([](auto f, auto l, auto& v) { x3::parse(f, l, (x3::int_ >> ':' >> x3::char_ | "---") % x3::eol, v); });
}

Output:

qi:
1:a
2:b
3:c
0:
5:e
0:
0:
7:h
0:
x3:
1:a
2:b
3:c
0:
5:e
0:
0:
7:h
0:
Kojoley commented 6 years ago

This is completely mind-blowing:

#include <boost/spirit/home/qi.hpp>
#include <boost/fusion/include/std_tuple.hpp>
#include <vector>
#include <iostream>

template <typename F>
void test(F f)
{
    std::vector<std::tuple<int, char>> v;
    char s[] = "1:a\n2:b\n3:c\n---\n5:e\n---\n---\n7:h\n---";
    f(std::begin(s), std::end(s), v);
    for (auto [x, y] : v) std::cout << ' ' << x << ':' << y;
    std::cout << '\n';
}

int main()
{
    namespace qi = boost::spirit::qi;
    std::cout << "#1:"; test([](auto f, auto l, auto& v) {
        qi::parse(f, l, ((qi::int_ >> ':' >> qi::char_) | "---") % qi::eol, v);
    });
    std::cout << "#2:"; test([](auto f, auto l, auto& v) {
        qi::parse(f, l, (-(qi::int_ >> ':' >> qi::char_) >> -qi::lit("---")) % qi::eol, v);
    });
    // does not compile for some reason
    //std::cout << "#3:"; test([](auto f, auto l, auto& v) {
    //    qi::parse(f, l, (-(qi::int_ >> ':' >> qi::char_) >> -qi::lit("---") | qi::eps) % qi::eol, v);
    //});
    std::cout << "#3:"; test([](auto f, auto l, auto& v) {
        qi::rule<decltype(f), std::tuple<int, char>> item = (qi::int_ >> ':' >> qi::char_);
        qi::parse(f, l, (-item >> -qi::lit("---") | qi::eps) % qi::eol, v);
    });
    // does not compile for some reason
    //std::cout << "#4:\n"; test([](auto f, auto l, auto& v) {
    //    qi::parse(f, l, ((qi::int_ >> ':' >> qi::char_) || "---") % qi::eol, v);
    //});
    std::cout << "#4:"; test([](auto f, auto l, auto& v) {
        qi::rule<decltype(f), std::tuple<int, char>> item = (qi::int_ >> ':' >> qi::char_);
        qi::parse(f, l, (item || "---") % qi::eol, v);
    });
}

Output:

#1: 1:a 2:b 3:c 0:  5:e 0:  0:  7:h 0:
#2: 1:a 2:b 3:c 0:  5:e 0:  0:  7:h 0:
#3: 1:a 2:b 3:c 5:e 7:h
#4: 1:a 2:b 3:c 5:e 7:h
djowel commented 6 years ago

That's a horrendous bug!

Kojoley commented 5 years ago

https://svn.boost.org/trac10/ticket/6444 looks like the same problem.

Kojoley commented 4 years ago

I am reopening it and retargeting to Qi