1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
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 #include <boost/detail/lightweight_test.hpp>
9 #include <boost/spirit/include/qi_operator.hpp>
10 #include <boost/spirit/include/qi_char.hpp>
11 #include <boost/spirit/include/qi_string.hpp>
12 #include <boost/spirit/include/qi_numeric.hpp>
13 #include <boost/spirit/include/qi_auxiliary.hpp>
14 #include <boost/spirit/include/qi_directive.hpp>
15 #include <boost/spirit/include/qi_nonterminal.hpp>
16 #include <boost/spirit/include/qi_action.hpp>
17 #include <boost/spirit/include/phoenix_core.hpp>
18 #include <boost/spirit/include/phoenix_operator.hpp>
19 #include <boost/spirit/include/phoenix_object.hpp>
20 #include <boost/spirit/include/phoenix_bind.hpp>
21 #include <boost/fusion/include/std_pair.hpp>
22
23 #include <string>
24 #include <cstring>
25 #include <iostream>
26 #include "test.hpp"
27
28 int
main()29 main()
30 {
31 using spirit_test::test_attr;
32 using spirit_test::test;
33
34 using namespace boost::spirit::ascii;
35 using namespace boost::spirit::qi::labels;
36 using boost::spirit::qi::locals;
37 using boost::spirit::qi::rule;
38 using boost::spirit::qi::int_;
39 using boost::spirit::qi::uint_;
40 using boost::spirit::qi::fail;
41 using boost::spirit::qi::on_error;
42 using boost::spirit::qi::debug;
43 using boost::spirit::qi::lit;
44
45 namespace phx = boost::phoenix;
46
47
48 { // show that ra = rb and ra %= rb works as expected
49 rule<char const*, int() > ra, rb;
50 int attr;
51
52 ra %= int_;
53 BOOST_TEST(test_attr("123", ra, attr));
54 BOOST_TEST(attr == 123);
55
56 rb %= ra;
57 BOOST_TEST(test_attr("123", rb, attr));
58 BOOST_TEST(attr == 123);
59
60 rb = ra;
61 BOOST_TEST(test_attr("123", rb, attr));
62 BOOST_TEST(attr == 123);
63 }
64
65 { // std::string as container attribute with auto rules
66
67 rule<char const*, std::string()> text;
68 text %= +(!char_(')') >> !char_('>') >> char_);
69 std::string attr;
70 BOOST_TEST(test_attr("x", text, attr));
71 BOOST_TEST(attr == "x");
72
73 // test deduced auto rule behavior
74 text = +(!char_(')') >> !char_('>') >> char_);
75 attr.clear();
76 BOOST_TEST(test_attr("x", text, attr));
77 BOOST_TEST(attr == "x");
78 }
79
80 { // error handling
81
82 using namespace boost::spirit::ascii;
83 using boost::phoenix::construct;
84 using boost::phoenix::bind;
85
86 rule<char const*> r;
87 r = '(' > int_ > ',' > int_ > ')';
88
89 on_error<fail>
90 (
91 r, std::cout
92 << phx::val("Error! Expecting: ")
93 << _4
94 << phx::val(", got: \"")
95 << construct<std::string>(_3, _2)
96 << phx::val("\"")
97 << std::endl
98 );
99
100 BOOST_TEST(test("(123,456)", r));
101 BOOST_TEST(!test("(abc,def)", r));
102 BOOST_TEST(!test("(123,456]", r));
103 BOOST_TEST(!test("(123;456)", r));
104 BOOST_TEST(!test("[123,456]", r));
105 }
106
107 { // specifying the encoding
108
109 typedef boost::spirit::char_encoding::iso8859_1 iso8859_1;
110 rule<char const*, iso8859_1> r;
111
112 r = no_case['\xE1'];
113 BOOST_TEST(test("\xC1", r));
114 r = no_case[char_('\xE1')];
115 BOOST_TEST(test("\xC1", r));
116
117 r = no_case[char_("\xE5-\xEF")];
118 BOOST_TEST(test("\xC9", r));
119 BOOST_TEST(!test("\xFF", r));
120
121 r = no_case["\xE1\xC1"];
122 BOOST_TEST(test("\xC1\xE1", r));
123 r = no_case[lit("\xE1\xC1")];
124 BOOST_TEST(test("\xC1\xE1", r));
125 }
126
127 {
128 typedef boost::variant<double, int> v_type;
129 rule<const char*, v_type()> r1 = int_;
130 v_type v;
131 BOOST_TEST(test_attr("1", r1, v) && v.which() == 1 &&
132 boost::get<int>(v) == 1);
133
134 typedef boost::optional<int> ov_type;
135 rule<const char*, ov_type()> r2 = int_;
136 ov_type ov;
137 BOOST_TEST(test_attr("1", r2, ov) && ov && boost::get<int>(ov) == 1);
138 }
139
140 // test handling of single element fusion sequences
141 {
142 using boost::fusion::vector;
143 using boost::fusion::at_c;
144 rule<const char*, vector<int>()> r = int_;
145
146 vector<int> v(0);
147 BOOST_TEST(test_attr("1", r, v) && at_c<0>(v) == 1);
148 }
149
150 {
151 using boost::fusion::vector;
152 using boost::fusion::at_c;
153 rule<const char*, vector<unsigned int>()> r = uint_;
154
155 vector<unsigned int> v(0);
156 BOOST_TEST(test_attr("1", r, v) && at_c<0>(v) == 1);
157 }
158
159 ///////////////////////////////////////////////////////////////////////////
160 {
161 using boost::spirit::qi::int_;
162 using boost::spirit::qi::_1;
163 using boost::spirit::qi::_val;
164 using boost::spirit::qi::space;
165 using boost::spirit::qi::space_type;
166
167 rule<const char*, int()> r1 = int_;
168 rule<const char*, int(), space_type> r2 = int_;
169
170 int i = 0;
171 int j = 0;
172 BOOST_TEST(test_attr("456", r1[_val = _1], i) && i == 456);
173 BOOST_TEST(test_attr(" 456", r2[_val = _1], j, space) && j == 456);
174 }
175
176 #if 0 // disabling test (can't fix)
177 {
178 using boost::spirit::qi::lexeme;
179 using boost::spirit::qi::alnum;
180
181 rule<const char*, std::string()> literal_;
182 literal_ = lexeme[ +(alnum | '_') ];
183
184 std::string attr;
185 BOOST_TEST(test_attr("foo_bar", literal_, attr) && attr == "foo_bar");
186 std::cout << attr << std::endl;
187 }
188 #endif
189
190 return boost::report_errors();
191 }
192
193