1/*=============================================================================
2 Copyright (c) 2001-2015 Joel de Guzman
3 Copyright (c) 2001-2011 Hartmut Kaiser
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7=============================================================================*/
8#include <boost/spirit/home/x3.hpp>
9#include <boost/fusion/include/adapt_struct.hpp>
10#include <boost/variant.hpp>
11#include <boost/fusion/include/vector.hpp>
12#include <boost/fusion/include/at.hpp>
13
14#include <string>
15#include <iostream>
16#include <vector>
17#include "test.hpp"
18
19struct di_ignore
20{
21 std::string text;
22};
23
24struct di_include
25{
26 std::string FileName;
27};
28
29BOOST_FUSION_ADAPT_STRUCT(di_ignore,
30 text
31)
32
33BOOST_FUSION_ADAPT_STRUCT(di_include,
34 FileName
35)
36
37struct undefined {};
38
39
40struct stationary : boost::noncopyable
41{
42 explicit stationary(int i) : val{i} {}
43 stationary& operator=(int i) { val = i; return *this; }
44
45 int val;
46};
47
48
49int
50main()
51{
52 using spirit_test::test;
53 using spirit_test::test_attr;
54
55 using boost::spirit::x3::attr;
56 using boost::spirit::x3::char_;
57 using boost::spirit::x3::int_;
58 using boost::spirit::x3::lit;
59 using boost::spirit::x3::unused_type;
60 using boost::spirit::x3::unused;
61 using boost::spirit::x3::omit;
62 using boost::spirit::x3::eps;
63
64 BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(char_ | char_);
65
66 {
67 BOOST_TEST((test("a", char_ | char_)));
68 BOOST_TEST((test("x", lit('x') | lit('i'))));
69 BOOST_TEST((test("i", lit('x') | lit('i'))));
70 BOOST_TEST((!test("z", lit('x') | lit('o'))));
71 BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
72 BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
73 BOOST_TEST((test("rock", lit("rock") | int_)));
74 BOOST_TEST((test("12345", lit("rock") | int_)));
75 }
76
77 {
78 typedef boost::variant<undefined, int, char> attr_type;
79 attr_type v;
80
81 BOOST_TEST((test_attr("12345", int_ | char_, v)));
82 BOOST_TEST(boost::get<int>(v) == 12345);
83
84 BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
85 BOOST_TEST(boost::get<int>(v) == 12345);
86
87 v = attr_type();
88 BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
89 BOOST_TEST(v.which() == 0);
90
91 BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
92 BOOST_TEST(boost::get<char>(v) == 'x');
93 }
94
95 { // Make sure that we are using the actual supplied attribute types
96 // from the variant and not the expected type.
97 boost::variant<int, std::string> v;
98 BOOST_TEST((test_attr("12345", int_ | +char_, v)));
99 BOOST_TEST(boost::get<int>(v) == 12345);
100
101 BOOST_TEST((test_attr("abc", int_ | +char_, v)));
102 BOOST_TEST(boost::get<std::string>(v) == "abc");
103
104 BOOST_TEST((test_attr("12345", +char_ | int_, v)));
105 BOOST_TEST(boost::get<std::string>(v) == "12345");
106 }
107
108 {
109 unused_type x;
110 BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
111 }
112
113 {
114 // test if alternatives with all components having unused
115 // attributes have an unused attribute
116
117 using boost::fusion::vector;
118 using boost::fusion::at_c;
119
120 vector<char, char> v;
121 BOOST_TEST((test_attr("abc",
122 char_ >> (omit[char_] | omit[char_]) >> char_, v)));
123 BOOST_TEST((at_c<0>(v) == 'a'));
124 BOOST_TEST((at_c<1>(v) == 'c'));
125 }
126
127 {
128 // Test that we can still pass a "compatible" attribute to
129 // an alternate even if its "expected" attribute is unused type.
130
131 std::string s;
132 BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
133 BOOST_TEST(s == "...");
134 }
135
136 { // make sure collapsing eps works as expected
137 // (compile check only)
138
139 using boost::spirit::x3::rule;
140 using boost::spirit::x3::eps;
141 using boost::spirit::x3::_attr;
142 using boost::spirit::x3::_val;
143
144 rule<class r1, wchar_t> r1;
145 rule<class r2, wchar_t> r2;
146 rule<class r3, wchar_t> r3;
147
148 auto f = [&](auto& ctx){ _val(ctx) = _attr(ctx); };
149
150 r3 = ((eps >> r1))[f];
151 r3 = ((r1) | r2)[f];
152 r3 = ((eps >> r1) | r2);
153 }
154
155 {
156 std::string s;
157 using boost::spirit::x3::eps;
158
159 // test having a variant<container, ...>
160 BOOST_TEST( (test_attr("a,b", (char_ % ',') | eps, s )) );
161 BOOST_TEST(s == "ab");
162 }
163
164 {
165 using boost::spirit::x3::eps;
166
167 // testing a sequence taking a container as attribute
168 std::string s;
169 BOOST_TEST( (test_attr("abc,a,b,c",
170 char_ >> char_ >> (char_ % ','), s )) );
171 BOOST_TEST(s == "abcabc");
172
173 // test having an optional<container> inside a sequence
174 s.erase();
175 BOOST_TEST( (test_attr("ab",
176 char_ >> char_ >> -(char_ % ','), s )) );
177 BOOST_TEST(s == "ab");
178
179 // test having a variant<container, ...> inside a sequence
180 s.erase();
181 BOOST_TEST( (test_attr("ab",
182 char_ >> char_ >> ((char_ % ',') | eps), s )) );
183 BOOST_TEST(s == "ab");
184 s.erase();
185 BOOST_TEST( (test_attr("abc",
186 char_ >> char_ >> ((char_ % ',') | eps), s )) );
187 BOOST_TEST(s == "abc");
188 }
189
190 {
191 //compile test only (bug_march_10_2011_8_35_am)
192 typedef boost::variant<double, std::string> value_type;
193
194 using boost::spirit::x3::rule;
195 using boost::spirit::x3::eps;
196
197 rule<class r1, value_type> r1;
198 auto r1_ = r1 = r1 | eps; // left recursive!
199
200 unused = r1_; // silence unused local warning
201 }
202
203 {
204 using boost::spirit::x3::rule;
205 typedef boost::variant<di_ignore, di_include> d_line;
206
207 rule<class ignore, di_ignore> ignore;
208 rule<class include, di_include> include;
209 rule<class line, d_line> line;
210
211 auto start =
212 line = include | ignore;
213
214 unused = start; // silence unused local warning
215 }
216
217 // single-element fusion vector tests
218 {
219 boost::fusion::vector<boost::variant<int, std::string>> fv;
220 BOOST_TEST((test_attr("12345", int_ | +char_, fv)));
221 BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fv)) == 12345);
222
223 boost::fusion::vector<boost::variant<int, std::string>> fvi;
224 BOOST_TEST((test_attr("12345", int_ | int_, fvi)));
225 BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fvi)) == 12345);
226 }
227
228 // alternative over single element sequences as part of another sequence
229 {
230 auto key1 = lit(s: "long") >> attr(long());
231 auto key2 = lit(s: "char") >> attr(char());
232 auto keys = key1 | key2;
233 auto pair = keys >> lit(s: "=") >> +char_;
234
235 boost::fusion::deque<boost::variant<long, char>, std::string> attr_;
236
237 BOOST_TEST(test_attr("long=ABC", pair, attr_));
238 BOOST_TEST(boost::get<long>(&boost::fusion::front(attr_)) != nullptr);
239 BOOST_TEST(boost::get<char>(&boost::fusion::front(attr_)) == nullptr);
240 }
241
242 { // ensure no unneeded synthesization, copying and moving occurred
243 auto p = '{' >> int_ >> '}';
244
245 stationary st { 0 };
246 BOOST_TEST(test_attr("{42}", p | eps | p, st));
247 BOOST_TEST_EQ(st.val, 42);
248 }
249
250 { // attributeless parsers must not insert values
251 std::vector<int> v;
252 BOOST_TEST(test_attr("1 2 3 - 5 - - 7 -", (int_ | '-') % ' ', v));
253 BOOST_TEST_EQ(v.size(), 5)
254 && BOOST_TEST_EQ(v[0], 1)
255 && BOOST_TEST_EQ(v[1], 2)
256 && BOOST_TEST_EQ(v[2], 3)
257 && BOOST_TEST_EQ(v[3], 5)
258 && BOOST_TEST_EQ(v[4], 7)
259 ;
260 }
261
262 { // regressing test for #603
263 using boost::spirit::x3::attr;
264 struct X {};
265 std::vector<boost::variant<std::string, int, X>> v;
266 BOOST_TEST(test_attr("xx42x9y", *(int_ | +char_('x') | 'y' >> attr(X{})), v));
267 BOOST_TEST_EQ(v.size(), 5);
268 }
269
270 { // sequence parser in alternative into container
271 std::string s;
272 BOOST_TEST(test_attr("abcbbcd",
273 *(char_('a') >> *(*char_('b') >> char_('c')) | char_('d')), s));
274 BOOST_TEST_EQ(s, "abcbbcd");
275 }
276
277 { // conversion between alternatives
278 struct X {};
279 struct Y {};
280 struct Z {};
281 boost::variant<X, Y, Z> v;
282 boost::variant<Y, X> x{X{}};
283 v = x; // boost::variant supports that convertion
284 auto const p = 'x' >> attr(x) | 'z' >> attr(Z{});
285 BOOST_TEST(test_attr("z", p, v));
286 BOOST_TEST(boost::get<Z>(&v) != nullptr);
287 BOOST_TEST(test_attr("x", p, v));
288 BOOST_TEST(boost::get<X>(&v) != nullptr);
289 }
290
291 { // regression test for #679
292 using Qaz = std::vector<boost::variant<int>>;
293 using Foo = std::vector<boost::variant<Qaz, int>>;
294 using Bar = std::vector<boost::variant<Foo, int>>;
295 Bar x;
296 BOOST_TEST(test_attr("abaabb", +('a' >> attr(Foo{}) | 'b' >> attr(int{})), x));
297 }
298
299 return boost::report_errors();
300}
301

source code of boost/libs/spirit/test/x3/alternative.cpp