1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Hartmut Kaiser |
3 | Copyright (c) 2001-2011 Joel de Guzman |
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/spirit/include/qi_attr_cast.hpp> |
9 | |
10 | #include <boost/fusion/include/struct.hpp> |
11 | #include <boost/fusion/include/nview.hpp> |
12 | |
13 | #include <boost/spirit/include/qi_char.hpp> |
14 | #include <boost/spirit/include/qi_string.hpp> |
15 | #include <boost/spirit/include/qi_numeric.hpp> |
16 | #include <boost/spirit/include/qi_operator.hpp> |
17 | #include <boost/spirit/include/qi_nonterminal.hpp> |
18 | #include <boost/spirit/include/qi_auxiliary.hpp> |
19 | |
20 | #include <iostream> |
21 | #include <vector> |
22 | #include <string> |
23 | #include "test.hpp" |
24 | |
25 | /////////////////////////////////////////////////////////////////////////////// |
26 | struct test_data |
27 | { |
28 | std::string s1; |
29 | std::string s2; |
30 | int i1; |
31 | double d1; |
32 | std::string s3; |
33 | }; |
34 | |
35 | BOOST_FUSION_ADAPT_STRUCT( |
36 | test_data, |
37 | (int, i1) |
38 | (std::string, s1) |
39 | (std::string, s2) |
40 | (std::string, s3) |
41 | (double, d1) |
42 | ) |
43 | |
44 | /////////////////////////////////////////////////////////////////////////////// |
45 | struct test_int_data1 |
46 | { |
47 | int i; |
48 | }; |
49 | |
50 | // we provide a custom attribute transformation taking copy of the actual |
51 | // attribute value, simulating more complex type transformations |
52 | namespace boost { namespace spirit { namespace traits |
53 | { |
54 | template <> |
55 | struct transform_attribute<test_int_data1, int, qi::domain> |
56 | { |
57 | typedef int type; |
58 | static int pre(test_int_data1& d) { return d.i; } |
59 | static void post(test_int_data1& d, int i) { d.i = i; } |
60 | static void fail(test_int_data1&) {} |
61 | }; |
62 | }}} |
63 | |
64 | /////////////////////////////////////////////////////////////////////////////// |
65 | struct test_int_data2 |
66 | { |
67 | int i; |
68 | }; |
69 | |
70 | // we provide a simple custom attribute transformation utilizing passing the |
71 | // actual attribute by reference |
72 | namespace boost { namespace spirit { namespace traits |
73 | { |
74 | template <> |
75 | struct transform_attribute<test_int_data2, int, qi::domain> |
76 | { |
77 | typedef int& type; |
78 | static int& pre(test_int_data2& d) { return d.i; } |
79 | static void post(test_int_data2&, int const&) {} |
80 | static void fail(test_int_data2&) {} |
81 | }; |
82 | }}} |
83 | |
84 | /////////////////////////////////////////////////////////////////////////////// |
85 | int |
86 | main() |
87 | { |
88 | using spirit_test::test_attr; |
89 | namespace qi = boost::spirit::qi; |
90 | namespace fusion = boost::fusion; |
91 | |
92 | // testing attribute reordering in a fusion sequence as explicit attribute |
93 | { |
94 | typedef fusion::result_of::as_nview<test_data, 1, 0, 4>::type |
95 | test_view; |
96 | |
97 | test_data d1 = { .s1: "" , .s2: "" , .i1: 0, .d1: 0.0, .s3: "" }; |
98 | test_view v1 = fusion::as_nview<1, 0, 4>(s&: d1); |
99 | BOOST_TEST(test_attr("s1,2,1.5" , |
100 | *(qi::char_ - ',') >> ',' >> qi::int_ >> ',' >> qi::double_, v1)); |
101 | BOOST_TEST(d1.i1 == 2 && d1.s1 == "s1" && d1.d1 == 1.5); |
102 | |
103 | test_data d2 = { .s1: "" , .s2: "" , .i1: 0, .d1: 0.0, .s3: "" }; |
104 | test_view v2 = fusion::as_nview<1, 0, 4>(s&: d2); |
105 | BOOST_TEST(test_attr("s1, 2, 1.5 " , |
106 | *(qi::char_ - ',') >> ',' >> qi::int_ >> ',' >> qi::double_, |
107 | v2, qi::space)); |
108 | BOOST_TEST(d2.i1 == 2 && d2.s1 == "s1" && d2.d1 == 1.5); |
109 | } |
110 | |
111 | { |
112 | // this won't work without the second template argument as *digit |
113 | // exposes a vector<char> as its attribute |
114 | std::string str; |
115 | BOOST_TEST(test_attr("123" |
116 | , qi::attr_cast<std::string, std::string>(*qi::digit), str)); |
117 | BOOST_TEST(str == "123" ); |
118 | } |
119 | |
120 | // testing attribute reordering in a fusion sequence involving a rule |
121 | { |
122 | typedef fusion::result_of::as_nview<test_data, 1, 0, 4>::type |
123 | test_view; |
124 | std::vector<test_data> v; |
125 | |
126 | qi::rule<char const*, test_view()> r1 = |
127 | *(qi::char_ - ',') >> ',' >> qi::int_ >> ',' >> qi::double_; |
128 | |
129 | BOOST_TEST(test_attr("s1,2,1.5\ns2,4,3.5" , r1 % qi::eol, v)); |
130 | BOOST_TEST(v.size() == 2 && |
131 | v[0].i1 == 2 && v[0].s1 == "s1" && v[0].d1 == 1.5 && |
132 | v[1].i1 == 4 && v[1].s1 == "s2" && v[1].d1 == 3.5); |
133 | |
134 | qi::rule<char const*, test_view(), qi::blank_type> r2 = |
135 | *(qi::char_ - ',') >> ',' >> qi::int_ >> ',' >> qi::double_; |
136 | |
137 | v.clear(); |
138 | BOOST_TEST(test_attr("s1, 2, 1.5 \n s2, 4, 3.5" , r2 % qi::eol, v, qi::blank)); |
139 | BOOST_TEST(v.size() == 2 && |
140 | v[0].i1 == 2 && v[0].s1 == "s1" && v[0].d1 == 1.5 && |
141 | v[1].i1 == 4 && v[1].s1 == "s2" && v[1].d1 == 3.5); |
142 | } |
143 | |
144 | // testing explicit transformation if attribute needs to be copied |
145 | { |
146 | test_int_data1 d = { .i: 0 }; |
147 | BOOST_TEST(test_attr("1" , qi::attr_cast(qi::int_), d)); |
148 | BOOST_TEST(d.i == 1); |
149 | BOOST_TEST(test_attr("2" , qi::attr_cast<test_int_data1>(qi::int_), d)); |
150 | BOOST_TEST(d.i == 2); |
151 | BOOST_TEST(test_attr("3" , qi::attr_cast<test_int_data1, int>(qi::int_), d)); |
152 | BOOST_TEST(d.i == 3); |
153 | } |
154 | |
155 | { |
156 | std::vector<test_int_data1> v; |
157 | |
158 | BOOST_TEST(test_attr("1,2" , qi::attr_cast(qi::int_) % ',', v)); |
159 | BOOST_TEST(v.size() == 2 && v[0].i == 1 && v[1].i == 2); |
160 | |
161 | v.clear(); |
162 | BOOST_TEST(test_attr("1,2" |
163 | , qi::attr_cast<test_int_data1>(qi::int_) % ',', v)); |
164 | BOOST_TEST(v.size() == 2 && v[0].i == 1 && v[1].i == 2); |
165 | |
166 | v.clear(); |
167 | BOOST_TEST(test_attr("1,2" |
168 | , qi::attr_cast<test_int_data1, int>(qi::int_) % ',', v)); |
169 | BOOST_TEST(v.size() == 2 && v[0].i == 1 && v[1].i == 2); |
170 | } |
171 | |
172 | return boost::report_errors(); |
173 | } |
174 | |