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///////////////////////////////////////////////////////////////////////////////
26struct test_data
27{
28 std::string s1;
29 std::string s2;
30 int i1;
31 double d1;
32 std::string s3;
33};
34
35BOOST_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///////////////////////////////////////////////////////////////////////////////
45struct 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
52namespace 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///////////////////////////////////////////////////////////////////////////////
65struct 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
72namespace 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///////////////////////////////////////////////////////////////////////////////
85int
86main()
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

source code of boost/libs/spirit/test/qi/attribute1.cpp