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/detail/lightweight_test.hpp>
9 #include <boost/spirit/home/x3.hpp>
10 #include <boost/fusion/include/vector.hpp>
11 #include <boost/fusion/include/at.hpp>
12 
13 #include <string>
14 #include <cstring>
15 #include <iostream>
16 #include "test.hpp"
17 
18 namespace x3 = boost::spirit::x3;
19 
20 int got_it = 0;
21 
22 struct my_rule_class
23 {
24     template <typename Iterator, typename Exception, typename Context>
25     x3::error_handler_result
on_errormy_rule_class26     on_error(Iterator&, Iterator const& last, Exception const& x, Context const&)
27     {
28         std::cout
29             << "Error! Expecting: "
30             << x.which()
31             << ", got: \""
32             << std::string(x.where(), last)
33             << "\""
34             << std::endl
35             ;
36         return x3::error_handler_result::fail;
37     }
38 
39     template <typename Iterator, typename Attribute, typename Context>
40     inline void
on_successmy_rule_class41     on_success(Iterator const&, Iterator const&, Attribute&, Context const&)
42     {
43         ++got_it;
44     }
45 };
46 
47 int
main()48 main()
49 {
50     using spirit_test::test_attr;
51     using spirit_test::test;
52 
53     using namespace boost::spirit::x3::ascii;
54     using boost::spirit::x3::rule;
55     using boost::spirit::x3::int_;
56     using boost::spirit::x3::lit;
57 
58     { // show that ra = rb and ra %= rb works as expected
59         rule<class a, int> ra;
60         rule<class b, int> rb;
61         int attr;
62 
63         auto ra_def = (ra %= int_);
64         BOOST_TEST(test_attr("123", ra_def, attr));
65         BOOST_TEST(attr == 123);
66 
67         auto rb_def = (rb %= ra_def);
68         BOOST_TEST(test_attr("123", rb_def, attr));
69         BOOST_TEST(attr == 123);
70 
71         auto rb_def2 = (rb = ra_def);
72         BOOST_TEST(test_attr("123", rb_def2, attr));
73         BOOST_TEST(attr == 123);
74     }
75 
76     { // show that ra %= rb works as expected with semantic actions
77         rule<class a, int> ra;
78         rule<class b, int> rb;
79         int attr;
80 
81         auto f = [](auto&){};
82         auto ra_def = (ra %= int_[f]);
83         BOOST_TEST(test_attr("123", ra_def, attr));
84         BOOST_TEST(attr == 123);
85 
86         auto ra_def2 = (rb = (ra %= int_[f]));
87         BOOST_TEST(test_attr("123", ra_def2, attr));
88         BOOST_TEST(attr == 123);
89     }
90 
91 
92     { // std::string as container attribute with auto rules
93 
94         std::string attr;
95 
96         // test deduced auto rule behavior
97 
98         auto text = rule<class text, std::string>()
99             = +(!char_(')') >> !char_('>') >> char_);
100 
101         attr.clear();
102         BOOST_TEST(test_attr("x", text, attr));
103         BOOST_TEST(attr == "x");
104     }
105 
106     { // error handling
107 
108         auto r = rule<my_rule_class, char const*>()
109             = '(' > int_ > ',' > int_ > ')';
110 
111         BOOST_TEST(test("(123,456)", r));
112         BOOST_TEST(!test("(abc,def)", r));
113         BOOST_TEST(!test("(123,456]", r));
114         BOOST_TEST(!test("(123;456)", r));
115         BOOST_TEST(!test("[123,456]", r));
116 
117         BOOST_TEST(got_it == 1);
118     }
119 
120     {
121         typedef boost::variant<double, int> v_type;
122         auto r1 = rule<class r1, v_type>()
123             = int_;
124         v_type v;
125         BOOST_TEST(test_attr("1", r1, v) && v.which() == 1 &&
126             boost::get<int>(v) == 1);
127 
128         typedef boost::optional<int> ov_type;
129         auto r2 = rule<class r2, ov_type>()
130             = int_;
131         ov_type ov;
132         BOOST_TEST(test_attr("1", r2, ov) && ov && boost::get<int>(ov) == 1);
133     }
134 
135     // test handling of single element fusion sequences
136     {
137         using boost::fusion::vector;
138         using boost::fusion::at_c;
139         auto r = rule<class r, vector<int>>()
140             = int_;
141 
142         vector<int> v(0);
143         BOOST_TEST(test_attr("1", r, v) && at_c<0>(v) == 1);
144     }
145 
146     { // attribute compatibility test
147         using boost::spirit::x3::rule;
148         using boost::spirit::x3::int_;
149 
150         auto const expr = int_;
151 
152         short i;
153         BOOST_TEST(test_attr("1", expr, i) && i == 1); // ok
154 
155         const rule< class int_rule, int > int_rule( "int_rule" );
156         auto const int_rule_def = int_;
157         auto const start  = int_rule = int_rule_def;
158 
159         short j;
160         BOOST_TEST(test_attr("1", start, j) && j == 1); // error
161     }
162 
163     return boost::report_errors();
164 }
165