1/*=============================================================================
2 Copyright (c) 2001-2015 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/spirit/home/x3.hpp>
9#include <boost/fusion/include/vector.hpp>
10#include <boost/fusion/include/at.hpp>
11
12#include <string>
13#include <cstring>
14#include <iostream>
15#include "test.hpp"
16
17namespace x3 = boost::spirit::x3;
18
19int got_it = 0;
20
21struct my_rule_class
22{
23 template <typename Iterator, typename Exception, typename Context>
24 x3::error_handler_result
25 on_error(Iterator&, Iterator const& last, Exception const& x, Context const&)
26 {
27 std::cout
28 << "Error! Expecting: "
29 << x.which()
30 << ", got: \""
31 << std::string(x.where(), last)
32 << "\""
33 << std::endl
34 ;
35 return x3::error_handler_result::fail;
36 }
37
38 template <typename Iterator, typename Attribute, typename Context>
39 inline void
40 on_success(Iterator const&, Iterator const&, Attribute&, Context const&)
41 {
42 ++got_it;
43 }
44};
45
46struct on_success_gets_preskipped_iterator
47{
48 static bool ok;
49
50 template <typename Iterator, typename Attribute, typename Context>
51 void on_success(Iterator before, Iterator& after, Attribute&, Context const&)
52 {
53 ok = ('b' == *before) && (++before == after);
54 }
55};
56bool on_success_gets_preskipped_iterator::ok = false;
57
58struct on_success_advance_iterator
59{
60 template <typename Iterator, typename Attribute, typename Context>
61 void on_success(Iterator const&, Iterator& after, Attribute&, Context const&)
62 {
63 ++after;
64 }
65};
66struct on_success_advance_iterator_mutref
67{
68 template <typename Iterator, typename Attribute, typename Context>
69 void on_success(Iterator&, Iterator& after, Attribute&, Context const&)
70 {
71 ++after;
72 }
73};
74struct on_success_advance_iterator_byval
75{
76 template <typename Iterator, typename Attribute, typename Context>
77 void on_success(Iterator, Iterator& after, Attribute&, Context const&)
78 {
79 ++after;
80 }
81};
82
83int
84main()
85{
86 using spirit_test::test_attr;
87 using spirit_test::test;
88
89 using namespace boost::spirit::x3::ascii;
90 using boost::spirit::x3::rule;
91 using boost::spirit::x3::int_;
92 using boost::spirit::x3::lit;
93
94 { // show that ra = rb and ra %= rb works as expected
95 rule<class a, int> ra;
96 rule<class b, int> rb;
97 int attr;
98
99 auto ra_def = (ra %= int_);
100 BOOST_TEST(test_attr("123", ra_def, attr));
101 BOOST_TEST(attr == 123);
102
103 auto rb_def = (rb %= ra_def);
104 BOOST_TEST(test_attr("123", rb_def, attr));
105 BOOST_TEST(attr == 123);
106
107 auto rb_def2 = (rb = ra_def);
108 BOOST_TEST(test_attr("123", rb_def2, attr));
109 BOOST_TEST(attr == 123);
110 }
111
112 { // show that ra %= rb works as expected with semantic actions
113 rule<class a, int> ra;
114 rule<class b, int> rb;
115 int attr;
116
117 auto f = [](auto&){};
118 auto ra_def = (ra %= int_[f]);
119 BOOST_TEST(test_attr("123", ra_def, attr));
120 BOOST_TEST(attr == 123);
121
122 auto ra_def2 = (rb = (ra %= int_[f]));
123 BOOST_TEST(test_attr("123", ra_def2, attr));
124 BOOST_TEST(attr == 123);
125 }
126
127
128 { // std::string as container attribute with auto rules
129
130 std::string attr;
131
132 // test deduced auto rule behavior
133
134 auto text = rule<class text_id, std::string>()
135 = +(!char_(')') >> !char_('>') >> char_);
136
137 attr.clear();
138 BOOST_TEST(test_attr("x", text, attr));
139 BOOST_TEST(attr == "x");
140 }
141
142 { // error handling
143
144 auto r = rule<my_rule_class, char const*>()
145 = '(' > int_ > ',' > int_ > ')';
146
147 BOOST_TEST(test("(123,456)", r));
148 BOOST_TEST(!test("(abc,def)", r));
149 BOOST_TEST(!test("(123,456]", r));
150 BOOST_TEST(!test("(123;456)", r));
151 BOOST_TEST(!test("[123,456]", r));
152
153 BOOST_TEST(got_it == 1);
154 }
155
156 { // on_success gets pre-skipped iterator
157 auto r = rule<on_success_gets_preskipped_iterator, char const*>()
158 = lit(s: "b");
159 BOOST_TEST(test("a b", 'a' >> r, lit(' ')));
160 BOOST_TEST(on_success_gets_preskipped_iterator::ok);
161 }
162
163 { // on_success handler mutable 'after' iterator
164 auto r1 = rule<on_success_advance_iterator, char const*>()
165 = lit(s: "ab");
166 BOOST_TEST(test("abc", r1));
167 auto r2 = rule<on_success_advance_iterator_mutref, char const*>()
168 = lit(s: "ab");
169 BOOST_TEST(test("abc", r2));
170 auto r3 = rule<on_success_advance_iterator_byval, char const*>()
171 = lit(s: "ab");
172 BOOST_TEST(test("abc", r3));
173 }
174
175 {
176 typedef boost::variant<double, int> v_type;
177 auto r1 = rule<class r1_id, v_type>()
178 = int_;
179 v_type v;
180 BOOST_TEST(test_attr("1", r1, v) && v.which() == 1 &&
181 boost::get<int>(v) == 1);
182
183 typedef boost::optional<int> ov_type;
184 auto r2 = rule<class r2_id, ov_type>()
185 = int_;
186 ov_type ov;
187 BOOST_TEST(test_attr("1", r2, ov) && ov && boost::get<int>(ov) == 1);
188 }
189
190 // test handling of single element fusion sequences
191 {
192 using boost::fusion::vector;
193 using boost::fusion::at_c;
194 auto r = rule<class r_id, vector<int>>()
195 = int_;
196
197 vector<int> v(0);
198 BOOST_TEST(test_attr("1", r, v) && at_c<0>(v) == 1);
199 }
200
201 { // attribute compatibility test
202 using boost::spirit::x3::rule;
203 using boost::spirit::x3::int_;
204
205 auto const expr = int_;
206
207 long long i;
208 BOOST_TEST(test_attr("1", expr, i) && i == 1); // ok
209
210 const rule< class int_rule, int > int_rule( "int_rule" );
211 auto const int_rule_def = int_;
212 auto const start = int_rule = int_rule_def;
213
214 long long j;
215 BOOST_TEST(test_attr("1", start, j) && j == 1); // error
216 }
217
218 return boost::report_errors();
219}
220

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