Skip to content

Commit 73a865b

Browse files
committed
Rework attribute for alternative parser
Implement the following rules * Remove duplicates * Simplify variant<X> to X * Make unused_type the first type of the variant * Transform variant<unused_type, T> to optional<T>
1 parent 859fd9c commit 73a865b

File tree

8 files changed

+228
-68
lines changed

8 files changed

+228
-68
lines changed

Diff for: doc/x3/quick_reference.qbk

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ a: vector<A>, b: vector<A> --> (a > b): vector<A>``]]
298298
[[__x3_alternative__ (`a | b`)]
299299
[``a: A, b: B --> (a | b): variant<A, B>
300300
a: A, b: Unused --> (a | b): optional<A>
301-
a: A, b: B, c: Unused --> (a | b | c): optional<variant<A, B> >
301+
a: A, b: B, c: Unused --> (a | b | c): variant<Unused, A, B>
302302
a: Unused, b: B --> (a | b): optional<B>
303303
a: Unused, b: Unused --> (a | b): Unused
304304
a: A, b: A --> (a | b): A``]]

Diff for: include/boost/spirit/home/x3/operator/alternative.hpp

+89-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
#if !defined(BOOST_SPIRIT_X3_ALTERNATIVE_JAN_07_2013_1131AM)
88
#define BOOST_SPIRIT_X3_ALTERNATIVE_JAN_07_2013_1131AM
99

10-
#include <boost/spirit/home/x3/support/traits/attribute_of_binary.hpp>
1110
#include <boost/spirit/home/x3/core/parser.hpp>
1211
#include <boost/spirit/home/x3/operator/detail/alternative.hpp>
13-
12+
#include <boost/spirit/home/x3/support/meta.hpp>
1413
#include <boost/variant/variant_fwd.hpp>
1514

15+
#include <type_traits>
16+
1617
namespace boost { namespace spirit { namespace x3
1718
{
1819
template <typename Left, typename Right>
@@ -53,11 +54,96 @@ namespace boost { namespace spirit { namespace x3
5354
}
5455
}}}
5556

57+
58+
namespace boost { namespace spirit { namespace x3 { namespace detail
59+
{
60+
template <typename Seq, typename... Ts>
61+
struct add_alternative_types_impl;
62+
63+
template <template<class...> typename Seq, typename... Ts>
64+
struct add_alternative_types_impl<Seq<Ts...>>
65+
{
66+
using type = Seq<Ts...>;
67+
};
68+
69+
template <template<class...> typename Seq, typename... Ts, typename U, typename... Us>
70+
struct add_alternative_types_impl<Seq<Ts...>, U, Us...>
71+
{
72+
using next_sequence = conditional_t<Seq<Ts...>::template contains<U>,
73+
Seq<Ts...>,
74+
conditional_t<std::is_same_v<std::remove_const_t<U>, unused_type>,
75+
typename Seq<Ts...>::template prepend<U>,
76+
typename Seq<Ts...>::template append<U>
77+
>
78+
>;
79+
80+
using type = typename add_alternative_types_impl<next_sequence, Us...>::type;
81+
};
82+
83+
template <typename Seq, typename... Ts>
84+
using add_alternative_types = typename add_alternative_types_impl<Seq, Ts...>::type;
85+
86+
template <typename... Seqs>
87+
struct merge_types_of_alternative_impl;
88+
89+
template <template <class...> typename Seq1, typename... T1s, template <class...> typename Seq2, typename... T2s>
90+
struct merge_types_of_alternative_impl<Seq1<T1s...>, Seq2<T2s...>>
91+
{
92+
using type = add_alternative_types<Seq1<T1s...>, T2s...>;
93+
};
94+
95+
template <typename... Seqs>
96+
using merge_types_of_alternative = typename merge_types_of_alternative_impl<Seqs...>::type;
97+
98+
template <typename P, typename C>
99+
struct get_types_of_alternative
100+
{
101+
using type = type_sequence<typename traits::attribute_of<P, C>::type>;
102+
};
103+
104+
template <typename L, typename R, typename C>
105+
struct get_types_of_alternative<alternative<L, R>, C>
106+
{
107+
using type = merge_types_of_alternative<
108+
typename get_types_of_alternative<L, C>::type,
109+
typename get_types_of_alternative<R, C>::type
110+
>;
111+
};
112+
113+
template <template <typename...> typename A, typename Seq>
114+
struct type_sequence_to_alternative_attribute;
115+
116+
template <template <typename...> typename A, template <typename...> typename Seq>
117+
struct type_sequence_to_alternative_attribute<A, Seq<>>
118+
{
119+
using type = unused_type;
120+
};
121+
122+
template <template <typename...> typename A, template <typename...> typename Seq, typename T, typename... Ts>
123+
struct type_sequence_to_alternative_attribute<A, Seq<T, Ts...>>
124+
{
125+
using type = conditional_t<sizeof...(Ts) == 0,
126+
T,
127+
A<T, Ts...>
128+
>;
129+
};
130+
131+
template <template <typename...> typename A, template <typename...> typename Seq, typename T>
132+
struct type_sequence_to_alternative_attribute<A, Seq<unused_type, T>>
133+
{
134+
using type = boost::optional<T>;
135+
};
136+
137+
template <template <typename...> class A, typename P, typename C>
138+
using attribute_of_alternative = type_sequence_to_alternative_attribute<A,
139+
typename get_types_of_alternative<P, C>::type>;
140+
}}}}
141+
56142
namespace boost { namespace spirit { namespace x3 { namespace traits
57143
{
58144
template <typename Left, typename Right, typename Context>
59145
struct attribute_of<x3::alternative<Left, Right>, Context>
60-
: x3::detail::attribute_of_binary<boost::variant, x3::alternative, Left, Right, Context> {};
146+
: x3::detail::attribute_of_alternative<boost::variant, x3::alternative<Left, Right>, Context> {};
61147
}}}}
62148

63149
#endif

Diff for: include/boost/spirit/home/x3/operator/sequence.hpp

+32-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
#if !defined(BOOST_SPIRIT_X3_SEQUENCE_JAN_06_2013_1015AM)
88
#define BOOST_SPIRIT_X3_SEQUENCE_JAN_06_2013_1015AM
99

10-
#include <boost/spirit/home/x3/support/traits/attribute_of_binary.hpp>
1110
#include <boost/spirit/home/x3/core/parser.hpp>
1211
#include <boost/spirit/home/x3/operator/detail/sequence.hpp>
1312
#include <boost/spirit/home/x3/directive/expect.hpp>
13+
#include <boost/spirit/home/x3/support/meta.hpp>
14+
#include <boost/spirit/home/x3/support/unused.hpp>
1415

1516
#include <boost/fusion/include/deque_fwd.hpp>
1617

@@ -64,11 +65,40 @@ namespace boost { namespace spirit { namespace x3
6465
}
6566
}}}
6667

68+
namespace boost { namespace spirit { namespace x3 { namespace detail
69+
{
70+
template <typename Attribute>
71+
struct types_of_sequence_init : type_sequence<Attribute> {};
72+
template <>
73+
struct types_of_sequence_init<unused_type> : type_sequence<> {};
74+
template <>
75+
struct types_of_sequence_init<unused_type const> : type_sequence<> {};
76+
77+
template <typename P, typename C>
78+
struct get_types_of_sequence
79+
: types_of_sequence_init<typename traits::attribute_of<P, C>::type> {};
80+
81+
template <typename L, typename R, typename C>
82+
struct get_types_of_sequence<x3::sequence<L, R>, C>
83+
: get_types_of_sequence<L, C>::template extend<get_types_of_sequence<R, C>> {};
84+
85+
template <template <typename...> class A, typename T, int = T::size>
86+
struct type_sequence_to_attribute { using type = typename T::template transfer_to<A>; };
87+
template <template <typename...> class A, typename T>
88+
struct type_sequence_to_attribute<A, T, 1> : T::template transfer_to<type_identity> {};
89+
template <template <typename...> class A, typename T>
90+
struct type_sequence_to_attribute<A, T, 0> { using type = unused_type; };
91+
92+
template <template <typename...> class A, typename P, typename C>
93+
using attribute_of_sequence = type_sequence_to_attribute<A,
94+
typename get_types_of_sequence<P, C>::type>;
95+
}}}}
96+
6797
namespace boost { namespace spirit { namespace x3 { namespace traits
6898
{
6999
template <typename Left, typename Right, typename Context>
70100
struct attribute_of<x3::sequence<Left, Right>, Context>
71-
: x3::detail::attribute_of_binary<fusion::deque, x3::sequence, Left, Right, Context> {};
101+
: x3::detail::attribute_of_sequence<fusion::deque, x3::sequence<Left, Right>, Context> {};
72102
}}}}
73103

74104
#endif

Diff for: include/boost/spirit/home/x3/support/meta.hpp

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*=============================================================================
2+
Copyright (c) 2020 Nikita Kniazev
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
=============================================================================*/
7+
8+
#ifndef BOOST_SPIRIT_X3_SUPPORT_META
9+
#define BOOST_SPIRIT_X3_SUPPORT_META
10+
11+
#include <boost/spirit/home/x3/support/unused.hpp>
12+
#include <type_traits>
13+
14+
namespace boost { namespace spirit { namespace x3 { namespace detail
15+
{
16+
template <typename... T>
17+
struct type_sequence
18+
{
19+
using type = type_sequence;
20+
21+
static const int size = sizeof...(T);
22+
23+
template <typename... U>
24+
using append = type_sequence<T..., U...>;
25+
26+
template <typename... U>
27+
using prepend = type_sequence<U..., T...>;
28+
29+
template <typename U>
30+
using extend = typename U::template prepend<T...>;
31+
32+
template <template <typename...> class U>
33+
using transfer_to = U<T...>;
34+
35+
template <typename U>
36+
static constexpr bool contains = (std::is_same_v<U, T> || ...);
37+
};
38+
39+
template <bool>
40+
struct conditional_impl
41+
{
42+
template <typename T, typename>
43+
using type = T;
44+
};
45+
46+
template <>
47+
struct conditional_impl<false>
48+
{
49+
template <typename, typename F>
50+
using type = F;
51+
};
52+
53+
template <bool B, typename T, typename F>
54+
using conditional_t = typename conditional_impl<B>::template type<T, F>;
55+
}}}}
56+
57+
#endif

Diff for: include/boost/spirit/home/x3/support/traits/attribute_of_binary.hpp

-62
This file was deleted.

Diff for: test/x3/Jamfile

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ project spirit-x3
3232
cxx14_return_type_deduction # grep -Er "auto[^\\(=\\)]+\(" *
3333
#cxx14_std_exchange # grep -r "exchange" *
3434
cxx14_variable_templates
35+
cxx17_fold_expressions
3536
]
3637
;
3738

Diff for: test/x3/alternative.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ struct stationary : boost::noncopyable
4545
int val;
4646
};
4747

48+
template <typename Expected, typename Expr>
49+
constexpr void test_attribute_of_alternative(Expr)
50+
{
51+
using namespace boost::spirit::x3;
52+
using namespace boost::spirit::x3::traits;
53+
54+
static_assert(std::is_same_v<Expected, typename attribute_of<Expr, unused_type>::type>);
55+
}
4856

4957
int
5058
main()
@@ -296,5 +304,25 @@ main()
296304
BOOST_TEST(test_attr("abaabb", +('a' >> attr(Foo{}) | 'b' >> attr(int{})), x));
297305
}
298306

307+
{ // compile checks
308+
using namespace boost::spirit::x3;
309+
310+
test_attribute_of_alternative<boost::variant<char, int>>(char_ | int_);
311+
test_attribute_of_alternative<boost::variant<char, int, double>>(char_ | int_ | double_);
312+
test_attribute_of_alternative<boost::variant<unused_type, char, int, double>>(char_ | int_ | double_ | eps);
313+
test_attribute_of_alternative<boost::variant<unused_type, char, int, double>>(char_ | int_ | double_ | eps | int_);
314+
test_attribute_of_alternative<boost::variant<unused_type, char, int, double>>(char_ | int_ | double_ | eps | int_ | eps);
315+
test_attribute_of_alternative<unused_type>(eps);
316+
test_attribute_of_alternative<boost::optional<int>>(eps | int_);
317+
test_attribute_of_alternative<boost::optional<int>>(eps | int_);
318+
test_attribute_of_alternative<unused_type>(eps | eps);
319+
test_attribute_of_alternative<int>(int_ | int_);
320+
test_attribute_of_alternative<int>(int_);
321+
322+
test_attribute_of_alternative<boost::variant<boost::fusion::deque<int, int>, char>>((int_ >> int_) | char_);
323+
test_attribute_of_alternative<boost::variant<unused_type, char, boost::fusion::deque<int, int>>>(char_ | (int_ >> int_) | eps);
324+
test_attribute_of_alternative<boost::optional<boost::fusion::deque<int, int>>>(eps | (int_ >> int_));
325+
}
326+
299327
return boost::report_errors();
300328
}

Diff for: test/x3/sequence.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
#include "test.hpp"
1616
#include "utils.hpp"
1717

18+
template <typename Expected, typename Expr>
19+
void test_attribute_of_sequence(Expr)
20+
{
21+
using namespace boost::spirit::x3;
22+
using namespace boost::spirit::x3::traits;
23+
24+
static_assert(std::is_same_v<Expected, typename attribute_of<Expr, unused_type>::type>);
25+
}
26+
1827
int
1928
main()
2029
{
@@ -493,5 +502,16 @@ main()
493502
BOOST_TEST_EQ(v.size(), 4);
494503
}
495504

505+
{ // compile checks only
506+
using namespace boost::spirit::x3;
507+
508+
test_attribute_of_sequence<boost::fusion::deque<int, int>>(int_ >> int_);
509+
test_attribute_of_sequence<int>(int_ >> eps);
510+
test_attribute_of_sequence<int>(eps >> int_);
511+
test_attribute_of_sequence<unused_type>(eps >> eps);
512+
test_attribute_of_sequence<int>(eps >> int_ >> eps);
513+
test_attribute_of_sequence<boost::fusion::deque<int, int>>(int_ >> eps >> eps >> int_ >> eps);
514+
}
515+
496516
return boost::report_errors();
497517
}

0 commit comments

Comments
 (0)