Opened 7 years ago

Closed 5 years ago

#12085 closed Bugs (fixed)

(a - b) === (!b >> a) does not hold in X3

Reported by: mikhail.strelnikov@… Owned by: Joel de Guzman
Milestone: To Be Determined Component: spirit
Version: Boost 1.61.0 Severity: Problem
Keywords: Cc:

Description

Following program checks that two grammars (GRAMMAR1 and GRAMMAR2) are giving the same result for x3 and qi. They don't.

GRAMMAR1 is (!b >> a), GRAMMAR2 is (a - b).

When x3 is used (USE_X3==1) output is:

1 d
1 abcd

When qi is used (USE_X3==0) output is:

1 abcd
1 abcd

#define USE_X3 1

#if USE_X3 == 1
#include <boost/spirit/home/x3.hpp>
#else
#include <boost/spirit/include/qi.hpp>
#endif

#include <iostream>
#include <string>
#include <vector>

#define GRAMMAR1 !lexeme[keywords >> !(alnum | '_')] >> lexeme[(alpha | '_') >> *(alnum | '_')]
#define GRAMMAR2 lexeme[(alpha | '_') >> *(alnum | '_')] - lexeme[keywords >> !(alnum | '_')]

int main()
{
    std::string str = "abcd";

    auto   end  = str.end();
#if USE_X3 == 1
    {
        using namespace boost::spirit::x3;
        symbols<> keywords({"k1", "k2", "k3"});
        
        {
            std::string v;
            auto begin = str.begin();
            bool full = boost::spirit::x3::parse(begin, end, GRAMMAR1, v) && begin == end;
            std::cout << full << " " << v << std::endl;
        }
        
        {
            std::string v;
            auto begin = str.begin();
            bool full = boost::spirit::x3::parse(begin, end, GRAMMAR2, v) && begin == end;
            std::cout << full << " " << v << std::endl;
        }
    }
#else
    {
        using namespace boost::spirit::qi;
        symbols<> keywords; keywords = "k1", "k2", "k3";
        
        {
            std::string v;
            auto begin = str.begin();
            bool full = boost::spirit::qi::parse(begin, end, GRAMMAR1, v) && begin == end;
            std::cout << full << " " << v << std::endl;
        }
    
        {
            std::string v;
            auto begin = str.begin();
            bool full = boost::spirit::qi::parse(begin, end, GRAMMAR2, v) && begin == end;
            std::cout << full << " " << v << std::endl;
        }
    }
#endif
}

Change History (9)

comment:1 by Joel de Guzman, 7 years ago

Is this a TST issue?

comment:2 by mikhail.strelnikov@…, 7 years ago

Yes. What do you think about https://github.com/boostorg/spirit/pull/181/commits/1f6d6c61849e89527c9b7be0818a16ce4833e8cf ? Should this work in x3 or should it not in qi?

comment:3 by Joel de Guzman, 7 years ago

I'm not sure. I still need to investigate. That said, if this one is a TST issue, then the test should be minimized further. It will be confusing to conflate the TST issue and the (!b >> a) and (a - b) issue together.

comment:4 by mikhail.strelnikov@…, 7 years ago

I think all this can be minimized to -

static_assert(traits::is_substitute<fusion::deque<char, std::string>, std::string>::value == 1, "");

or even simpler

static_assert(traits::is_substitute<char, std::string>::value == 1, "");

Which is kind of makes sense - if we have a char, we can put it to a string.

If this compiles, then test passes. I've tried this by adding specialization

template <typename T, typename Attribute>
    struct is_substitute<T, Attribute, typename enable_if<is_container<Attribute> >::type>
        : is_substitute<typename mpl::eval_if
            <
                fusion::traits::is_sequence<T>, 
                fusion::result_of::front<T>,
                mpl::identity<T>
            >::type, typename container_value<Attribute>::type> {};

comment:5 by Joel de Guzman, 7 years ago

So it's not a TST issue then. An is_substitute specialization would be easy to add.

in reply to:  5 comment:6 by Joel de Guzman, 7 years ago

Replying to djowel:

So it's not a TST issue then. An is_substitute specialization would be easy to add. Does your specialization compile? Seems too complicated.

comment:7 by Nikita Kniazev <nok.raven@…>, 5 years ago

comment:8 by Nikita Kniazev <nok.raven@…>, 5 years ago

comment:9 by Joel de Guzman, 5 years ago

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.