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/detail/lightweight_test.hpp>
9 #include <boost/spirit/home/x3.hpp>
10 #include <boost/fusion/include/adapt_struct.hpp>
11 #include <boost/variant.hpp>
12 #include <boost/fusion/include/vector.hpp>
13 #include <boost/fusion/include/at.hpp>
14
15 #include <string>
16 #include <iostream>
17 #include <vector>
18 #include "test.hpp"
19
20 struct di_ignore
21 {
22 std::string text;
23 };
24
25 struct di_include
26 {
27 std::string FileName;
28 };
29
30 BOOST_FUSION_ADAPT_STRUCT(di_ignore,
31 text
32 )
33
34 BOOST_FUSION_ADAPT_STRUCT(di_include,
35 FileName
36 )
37
38 struct undefined {};
39
40
41 struct stationary : boost::noncopyable
42 {
stationarystationary43 explicit stationary(int i) : val{i} {}
44 // TODO: fix unneeded self move in alternative
operator =stationary45 stationary& operator=(stationary&&) { std::abort(); }
operator =stationary46 stationary& operator=(int i) { val = i; return *this; }
47
48 int val;
49 };
50
51
52 int
main()53 main()
54 {
55 using spirit_test::test;
56 using spirit_test::test_attr;
57
58 using boost::spirit::x3::attr;
59 using boost::spirit::x3::char_;
60 using boost::spirit::x3::int_;
61 using boost::spirit::x3::lit;
62 using boost::spirit::x3::unused_type;
63 using boost::spirit::x3::unused;
64 using boost::spirit::x3::omit;
65 using boost::spirit::x3::eps;
66
67
68 {
69 BOOST_TEST((test("a", char_ | char_)));
70 BOOST_TEST((test("x", lit('x') | lit('i'))));
71 BOOST_TEST((test("i", lit('x') | lit('i'))));
72 BOOST_TEST((!test("z", lit('x') | lit('o'))));
73 BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
74 BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
75 BOOST_TEST((test("rock", lit("rock") | int_)));
76 BOOST_TEST((test("12345", lit("rock") | int_)));
77 }
78
79 {
80 typedef boost::variant<undefined, int, char> attr_type;
81 attr_type v;
82
83 BOOST_TEST((test_attr("12345", int_ | char_, v)));
84 BOOST_TEST(boost::get<int>(v) == 12345);
85
86 BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
87 BOOST_TEST(boost::get<int>(v) == 12345);
88
89 v = attr_type();
90 BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
91 BOOST_TEST(v.which() == 0);
92
93 BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
94 BOOST_TEST(boost::get<char>(v) == 'x');
95 }
96
97 { // Make sure that we are using the actual supplied attribute types
98 // from the variant and not the expected type.
99 boost::variant<int, std::string> v;
100 BOOST_TEST((test_attr("12345", int_ | +char_, v)));
101 BOOST_TEST(boost::get<int>(v) == 12345);
102
103 BOOST_TEST((test_attr("abc", int_ | +char_, v)));
104 BOOST_TEST(boost::get<std::string>(v) == "abc");
105
106 BOOST_TEST((test_attr("12345", +char_ | int_, v)));
107 BOOST_TEST(boost::get<std::string>(v) == "12345");
108 }
109
110 {
111 unused_type x;
112 BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
113 }
114
115 {
116 // test if alternatives with all components having unused
117 // attributes have an unused attribute
118
119 using boost::fusion::vector;
120 using boost::fusion::at_c;
121
122 vector<char, char> v;
123 BOOST_TEST((test_attr("abc",
124 char_ >> (omit[char_] | omit[char_]) >> char_, v)));
125 BOOST_TEST((at_c<0>(v) == 'a'));
126 BOOST_TEST((at_c<1>(v) == 'c'));
127 }
128
129 {
130 // Test that we can still pass a "compatible" attribute to
131 // an alternate even if its "expected" attribute is unused type.
132
133 std::string s;
134 BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
135 BOOST_TEST(s == "...");
136 }
137
138 { // make sure collapsing eps works as expected
139 // (compile check only)
140
141 using boost::spirit::x3::rule;
142 using boost::spirit::x3::eps;
143 using boost::spirit::x3::_attr;
144 using boost::spirit::x3::_val;
145
146 rule<class r1, wchar_t> r1;
147 rule<class r2, wchar_t> r2;
148 rule<class r3, wchar_t> r3;
149
150 auto f = [&](auto& ctx){ _val(ctx) = _attr(ctx); };
151
152 r3 = ((eps >> r1))[f];
153 r3 = ((r1) | r2)[f];
154 r3 = ((eps >> r1) | r2);
155 }
156
157 {
158 std::string s;
159 using boost::spirit::x3::eps;
160
161 // test having a variant<container, ...>
162 BOOST_TEST( (test_attr("a,b", (char_ % ',') | eps, s )) );
163 BOOST_TEST(s == "ab");
164 }
165
166 {
167 using boost::spirit::x3::eps;
168
169 // testing a sequence taking a container as attribute
170 std::string s;
171 BOOST_TEST( (test_attr("abc,a,b,c",
172 char_ >> char_ >> (char_ % ','), s )) );
173 BOOST_TEST(s == "abcabc");
174
175 // test having an optional<container> inside a sequence
176 s.erase();
177 BOOST_TEST( (test_attr("ab",
178 char_ >> char_ >> -(char_ % ','), s )) );
179 BOOST_TEST(s == "ab");
180
181 // test having a variant<container, ...> inside a sequence
182 s.erase();
183 BOOST_TEST( (test_attr("ab",
184 char_ >> char_ >> ((char_ % ',') | eps), s )) );
185 BOOST_TEST(s == "ab");
186 s.erase();
187 BOOST_TEST( (test_attr("abc",
188 char_ >> char_ >> ((char_ % ',') | eps), s )) );
189 BOOST_TEST(s == "abc");
190 }
191
192 {
193 //compile test only (bug_march_10_2011_8_35_am)
194 typedef boost::variant<double, std::string> value_type;
195
196 using boost::spirit::x3::rule;
197 using boost::spirit::x3::eps;
198
199 rule<class r1, value_type> r1;
200 auto r1_ = r1 = r1 | eps; // left recursive!
201
202 unused = r1_; // silence unused local warning
203 }
204
205 {
206 using boost::spirit::x3::rule;
207 typedef boost::variant<di_ignore, di_include> d_line;
208
209 rule<class ignore, di_ignore> ignore;
210 rule<class include, di_include> include;
211 rule<class line, d_line> line;
212
213 auto start =
214 line = include | ignore;
215
216 unused = start; // silence unused local warning
217 }
218
219 // single-element fusion vector tests
220 {
221 boost::fusion::vector<boost::variant<int, std::string>> fv;
222 BOOST_TEST((test_attr("12345", int_ | +char_, fv)));
223 BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fv)) == 12345);
224
225 boost::fusion::vector<boost::variant<int, std::string>> fvi;
226 BOOST_TEST((test_attr("12345", int_ | int_, fvi)));
227 BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fvi)) == 12345);
228 }
229
230 // alternative over single element sequences as part of another sequence
231 {
232 auto key1 = lit("long") >> attr(long());
233 auto key2 = lit("char") >> attr(char());
234 auto keys = key1 | key2;
235 auto pair = keys >> lit("=") >> +char_;
236
237 boost::fusion::deque<boost::variant<long, char>, std::string> attr_;
238
239 BOOST_TEST(test_attr("long=ABC", pair, attr_));
240 BOOST_TEST(boost::get<long>(&boost::fusion::front(attr_)) != nullptr);
241 BOOST_TEST(boost::get<char>(&boost::fusion::front(attr_)) == nullptr);
242 }
243
244 { // ensure no unneded synthesization, copying and moving occured
245 auto p = '{' >> int_ >> '}';
246
247 stationary st { 0 };
248 BOOST_TEST(test_attr("{42}", p | eps | p, st));
249 BOOST_TEST_EQ(st.val, 42);
250 }
251
252 return boost::report_errors();
253 }
254