• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2011 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/mpl/print.hpp>
10 #include <boost/spirit/include/qi_operator.hpp>
11 #include <boost/spirit/include/qi_char.hpp>
12 #include <boost/spirit/include/qi_string.hpp>
13 #include <boost/spirit/include/qi_numeric.hpp>
14 #include <boost/spirit/include/qi_directive.hpp>
15 #include <boost/spirit/include/qi_action.hpp>
16 #include <boost/spirit/include/qi_nonterminal.hpp>
17 #include <boost/spirit/include/qi_auxiliary.hpp>
18 #include <boost/spirit/include/qi_rule.hpp>
19 #include <boost/spirit/include/support_argument.hpp>
20 #include <boost/spirit/include/phoenix_core.hpp>
21 #include <boost/spirit/include/phoenix_operator.hpp>
22 #include <boost/fusion/include/adapt_struct.hpp>
23 #include <boost/variant.hpp>
24 #include <boost/assert.hpp>
25 
26 #include <string>
27 #include <iostream>
28 #include <vector>
29 #include "test.hpp"
30 
31 struct test_action
32 {
test_actiontest_action33     test_action(char last)
34       : last_(last) {}
35 
36     template<typename Context>
operator ()test_action37     void operator()(std::vector<char> const& v, Context const&, bool&) const
38     {
39         BOOST_TEST(v.size() == 4 &&
40             v[0] == 'a' && v[1] == 'b' && v[2] == '1' && v[3] == last_);
41     }
42 
43     char last_;
44 };
45 
46 struct test_action_2
47 {
48     typedef std::vector<boost::optional<char>	> result_type;
49 
50     template<typename Context>
operator ()test_action_251     void operator()(result_type const& v, Context const&, bool&) const
52     {
53         BOOST_TEST(v.size() == 5 &&
54             !v[0] && v[1] == 'a' && v[2] == 'b' && v[3] == '1' && v[4] == '2');
55     }
56 };
57 
58 struct DIgnore
59 {
60     std::string text;
61 };
62 
63 struct DInclude
64 {
65     std::string FileName;
66 };
67 
68 BOOST_FUSION_ADAPT_STRUCT(
69     DIgnore,
70     (std::string, text)
71 )
72 
73 BOOST_FUSION_ADAPT_STRUCT(
74     DInclude,
75     (std::string, FileName)
76 )
77 
78 int
main()79 main()
80 {
81     using spirit_test::test;
82     using spirit_test::test_attr;
83 
84     using boost::spirit::ascii::char_;
85     using boost::spirit::qi::int_;
86     using boost::spirit::qi::lit;
87     using boost::spirit::qi::unused_type;
88     using boost::spirit::qi::_1;
89     using boost::spirit::qi::omit;
90 
91     {
92         BOOST_TEST((test("a", char_ | char_)));
93         BOOST_TEST((test("x", lit('x') | lit('i'))));
94         BOOST_TEST((test("i", lit('x') | lit('i'))));
95         BOOST_TEST((!test("z", lit('x') | lit('o'))));
96         BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
97         BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
98         BOOST_TEST((test("rock", lit("rock") | int_)));
99         BOOST_TEST((test("12345", lit("rock") | int_)));
100     }
101 
102     {
103         boost::variant<unused_type, int, char> v;
104 
105         BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
106         BOOST_TEST(boost::get<int>(v) == 12345);
107 
108         BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
109         BOOST_TEST(v.which() == 1);
110 
111         BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
112         BOOST_TEST(boost::get<char>(v) == 'x');
113     }
114 
115     {   // Make sure that we are using the actual supplied attribute types
116         // from the variant and not the expected type.
117         // $$$ Fixed: <2/19/2011> JDG $$$
118          boost::variant<int, std::string> v;
119          BOOST_TEST((test_attr("12345", int_ | +char_, v)));
120          BOOST_TEST(boost::get<int>(v) == 12345);
121 
122          BOOST_TEST((test_attr("abc", int_ | +char_, v)));
123          BOOST_TEST(boost::get<std::string>(v) == "abc");
124 
125          BOOST_TEST((test_attr("12345", +char_ | int_, v)));
126          BOOST_TEST(boost::get<std::string>(v) == "12345");
127     }
128 
129     {   // test action
130 
131         namespace phx = boost::phoenix;
132         boost::optional<boost::variant<int, char> > v;
133 
134         BOOST_TEST((test("12345", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
135         BOOST_TEST(boost::get<int>(boost::get(v)) == 12345);
136         BOOST_TEST((test("rock", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
137         BOOST_TEST(!v);
138     }
139 
140     {
141         unused_type x;
142         BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
143     }
144 
145     {
146         // test if alternatives with all components having unused
147         // attributes have an unused attribute
148 
149         using boost::fusion::vector;
150         using boost::fusion::at_c;
151 
152         vector<char, char> v;
153         BOOST_TEST((test_attr("abc",
154             char_ >> (omit[char_] | omit[char_]) >> char_, v)));
155         BOOST_TEST((at_c<0>(v) == 'a'));
156         BOOST_TEST((at_c<1>(v) == 'c'));
157     }
158 
159     {
160         // Test that we can still pass a "compatible" attribute to
161         // an alternate even if its "expected" attribute is unused type.
162 
163         std::string s;
164         BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
165         BOOST_TEST(s == "...");
166     }
167 
168     {   // make sure collapsing eps works as expected
169         // (compile check only)
170 
171         using boost::spirit::qi::rule;
172         using boost::spirit::qi::_val;
173         using boost::spirit::qi::_1;
174         using boost::spirit::eps;
175         rule<const wchar_t*, wchar_t()> r1, r2, r3;
176 
177         r3  = ((eps >> r1))[_val += _1];
178         r3  = ((r1 ) | r2)[_val += _1];
179 
180         r3 %= ((eps >> r1) | r2);
181         r3 = ((eps >> r1) | r2)[_val += _1];
182     }
183 
184     // make sure the attribute of an alternative gets properly collapsed
185     {
186         using boost::spirit::qi::lexeme;
187         using boost::spirit::ascii::alnum;
188         using boost::spirit::ascii::alpha;
189         using boost::spirit::ascii::digit;
190         using boost::spirit::ascii::string;
191         namespace phx = boost::phoenix;
192 
193 
194         BOOST_TEST( (test("ab1_", (*(alnum | char_('_')))[test_action('_')])) );
195         BOOST_TEST( (test("ab12", (*(alpha | digit))[test_action('2')])) );
196 
197         BOOST_TEST( (test("abcab12", (*("abc" | alnum))[test_action_2()])) );
198 
199         std::vector<boost::optional<char> > v;
200         BOOST_TEST( (test("x,y,z", (*(',' | char_))[phx::ref(v) = _1])) );
201         BOOST_ASSERT(v[0] == 'x');
202         BOOST_ASSERT(!v[1]);
203         BOOST_ASSERT(v[2] == 'y');
204         BOOST_ASSERT(!v[3]);
205         BOOST_ASSERT(v[4] == 'z');
206     }
207 
208     {
209         using boost::spirit::qi::eps;
210 
211         // testing a sequence taking a container as attribute
212         std::string s;
213         BOOST_TEST( (test_attr("abc,a,b,c",
214             char_ >> char_ >> (char_ % ','), s )) );
215         BOOST_TEST(s == "abcabc");
216 
217         // test having an optional<container> inside a sequence
218         s.erase();
219         BOOST_TEST( (test_attr("ab",
220             char_ >> char_ >> -(char_ % ','), s )) );
221         BOOST_TEST(s == "ab");
222 
223         // test having a variant<container, ...> inside a sequence
224         s.erase();
225         BOOST_TEST( (test_attr("ab",
226             char_ >> char_ >> ((char_ % ',') | eps), s )) );
227         BOOST_TEST(s == "ab");
228         s.erase();
229         BOOST_TEST( (test_attr("abc",
230             char_ >> char_ >> ((char_ % ',') | eps), s )) );
231         BOOST_TEST(s == "abc");
232     }
233 
234     {
235         using boost::spirit::qi::int_;
236 
237         int i = 0;
238         BOOST_TEST( (test_attr("10", int_(5) | int_(10), i)) );
239         BOOST_TEST(i == 10);
240     }
241 
242     {
243 #ifdef SPIRIT_NO_COMPILE_CHECK
244         //compile test only (bug_march_10_2011_8_35_am)
245         // TODO: does not work as intended with std <= c++03
246         typedef boost::variant<double, std::string> value_type;
247 
248         using boost::spirit::qi::rule;
249         using boost::spirit::qi::eps;
250         rule<std::string::const_iterator, value_type()> r1 = r1 | eps;
251 #endif
252     }
253 
254     {
255         using boost::spirit::qi::rule;
256         typedef boost::variant<DIgnore, DInclude> DLine;
257 
258         rule<char*, DIgnore()> ignore;
259         rule<char*, DInclude()> include;
260         rule<char*, DLine()> line = include | ignore;
261     }
262 
263     return boost::report_errors();
264 }
265 
266