]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
92f5a8d4 TL |
40 | |
41 | struct stationary : boost::noncopyable | |
42 | { | |
43 | explicit stationary(int i) : val{i} {} | |
44 | // TODO: fix unneeded self move in alternative | |
45 | stationary& operator=(stationary&&) { std::abort(); } | |
46 | stationary& operator=(int i) { val = i; return *this; } | |
47 | ||
48 | int val; | |
49 | }; | |
50 | ||
51 | ||
7c673cae FG |
52 | int |
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; | |
92f5a8d4 | 65 | using boost::spirit::x3::eps; |
7c673cae FG |
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 | ||
92f5a8d4 TL |
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 | ||
7c673cae FG |
252 | return boost::report_errors(); |
253 | } |