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