Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X3: Kleene star can't into single-element sequence #178

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

hia3
Copy link
Contributor

@hia3 hia3 commented Mar 19, 2016

This will fail to compile with error "'value_type': is not a member of 'ast::a3'".

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/define_struct_inline.hpp>

#include <string>
#include <vector>

namespace ast
{
    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a1,
        (std::string, v)
    )

    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a2,
        (a1, v1)
        (std::vector<double>, v2)
    )

    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a3,
        (std::vector<a2>, v1)
    )
}

using namespace boost::spirit::x3;

auto a1 = rule<class i1, ast::a1>{} = lexeme[+alpha];

auto a2 = rule<class i2, ast::a2>{} = a1 >> '(' >> -(double_ % ',') >> ')';

auto a3 = rule<class i3, ast::a3>{} = *(a2 >> ';');

using data = ast::a3;

int main()
{
    std::string script = "foo(1,2,3);";

    auto begin = script.begin();
    auto   end = script.end();

    data v;

    bool ok = (boost::spirit::x3::phrase_parse(begin, end, a3, space, v) && begin == end);
}

Fixed by adding container_value specialization: for single-element fusion sequence return container_value of that one element.

This will fail to compile with error "'value_type': is not a member of 'ast::a3'".


#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/define_struct_inline.hpp>

#include <string>
#include <vector>

namespace ast
{
    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a1,
        (std::string, v)
    )

    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a2,
        (a1, v1)
        (std::vector<double>, v2)
    )

    BOOST_FUSION_DEFINE_STRUCT_INLINE
    (
        a3,
        (std::vector<a2>, v1)
    )
}

using namespace boost::spirit::x3;

auto a1 = rule<class i1, ast::a1>{} = lexeme[+alpha];

auto a2 = rule<class i2, ast::a2>{} = a1 >> '(' >> -(double_ % ',') >> ')';

auto a3 = rule<class i3, ast::a3>{} = *(a2 >> ';');

using data = ast::a3;

int main()
{
    std::string script = "foo(1,2,3);";

    auto begin = script.begin();
    auto   end = script.end();

    data v;

    bool ok = (boost::spirit::x3::phrase_parse(begin, end, a3, space, v) && begin == end);
}


Fixed by adding container_value specialization: for single-element fusion sequence return container_value of that one element.
@hia3
Copy link
Contributor Author

hia3 commented Mar 19, 2016

Btw, adding #define BOOST_SPIRIT_X3_DEBUG will break this sample program again.

@djowel
Copy link
Collaborator

djowel commented Mar 19, 2016

I'm not sure about this one. Why do you have to wrap the container into a fusion vector? Why not simply use std::vector and std::vectorstd::vector ?

@hia3
Copy link
Contributor Author

hia3 commented Mar 19, 2016

Why not?

I'm not saying "you have to". This might be the result of simplification of some existing code. Do you want to not to compile simpler version of the code? Then static_assert would help a lot. Or this might be the 1st parser someone new to the library (like myself) trying to write.

If I'd adapting the existring struct, I could write using value_type = whatever;, but with BOOST_FUSION_DEFINE_STRUCT_INLINE there is no way I can do it.

Why variable here https://github.com/boostorg/spirit/blob/develop/example/x3/calc/calc9/ast.hpp#L27 is not a string?

@hia3
Copy link
Contributor Author

hia3 commented Mar 19, 2016

Btw, ast::a3 is unchanged from my previous pull request (it was single element seqence too). Only thing changed is a3 rule from this:

auto a3_v1 = rule<class a3_v1, std::vector<ast::a2>>{} = *(a2 >> ';');
auto a3    = rule<class i3, ast::a3>{}                 = a3_v1;

to this

auto a3    = rule<class i3, ast::a3>{}                 = *(a2 >> ';');

And now it suddenly requires value_type to be defined.

@djowel
Copy link
Collaborator

djowel commented Mar 19, 2016

I'll have to think about this some more as it introduces a new behavior. The previous behavior in which you provided a patch for is suspicious to begin with. What we should probably do is to distill the test code to the bare essentials so I (we) can analyze and reason out with the correct behavior. I fear that we are opening a can of worms if we allow single-element-tuple-with-container == container.

@Kojoley
Copy link
Collaborator

Kojoley commented Sep 21, 2018

MWE:

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/define_struct_inline.hpp>
#include <string>

namespace ast
{
BOOST_FUSION_DEFINE_STRUCT_INLINE
(
    a3,
    (std::vector<int>, v1)
)
}

int main()
{
    namespace x3 = boost::spirit::x3;

    auto test = [](std::string s, auto&& p)
    {
        ast::a3 v;

        auto it = s.begin();
        return (x3::phrase_parse(it, s.end(), p, x3::space, v) && it == s.end());
    };

    test("1 2 3 ", *x3::int_);          // OK
    test("1;2;3 ",  x3::int_ % ';');    // OK
    test("1;2;3;", *(x3::int_ >> ';')); // Fail to compile
}

@Kojoley Kojoley changed the title Kleene star can't into single-element sequence X3: Kleene star can't into single-element sequence Sep 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants