1 /*=============================================================================
2 Copyright (c) 2001-2012 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/adapt_struct.hpp>
11 #include <boost/fusion/include/std_pair.hpp>
12
13 #include <boost/variant.hpp>
14 #include <string>
15 #include <vector>
16 #include <cstring>
17 #include <iostream>
18 #include "test.hpp"
19
20 using boost::spirit::x3::_val;
21 namespace x3 = boost::spirit::x3;
22
23 struct f
24 {
25 template <typename Context>
operator ()f26 void operator()(Context const& ctx) const
27 {
28 _val(ctx) += _attr(ctx);
29 }
30 };
31
32
33 struct stationary : boost::noncopyable
34 {
stationarystationary35 explicit stationary(int i) : val{i} {}
operator =stationary36 stationary& operator=(int i) { val = i; return *this; }
37
38 int val;
39 };
40
41
42 namespace check_stationary {
43
44 boost::spirit::x3::rule<class a_r, stationary> const a;
45 boost::spirit::x3::rule<class b_r, stationary> const b;
46
47 auto const a_def = '{' >> boost::spirit::x3::int_ >> '}';
48 auto const b_def = a;
49
50 BOOST_SPIRIT_DEFINE(a, b)
51
52 }
53
54 namespace check_recursive {
55
56 using node_t = boost::make_recursive_variant<
57 int,
58 std::vector<boost::recursive_variant_>
59 >::type;
60
61 boost::spirit::x3::rule<class grammar_r, node_t> const grammar;
62
63 auto const grammar_def = '[' >> grammar % ',' >> ']' | boost::spirit::x3::int_;
64
65 BOOST_SPIRIT_DEFINE(grammar)
66
67 }
68
69 namespace check_recursive_scoped {
70
71 using check_recursive::node_t;
72
73 x3::rule<class intvec_r, node_t> const intvec;
74 auto const grammar = intvec = '[' >> intvec % ',' >> ']' | x3::int_;
75
76 }
77
78 struct recursive_tuple
79 {
80 int value;
81 std::vector<recursive_tuple> children;
82 };
83 BOOST_FUSION_ADAPT_STRUCT(recursive_tuple,
84 value, children)
85
86 // regression test for #461
87 namespace check_recursive_tuple {
88
89 x3::rule<class grammar_r, recursive_tuple> const grammar;
90 auto const grammar_def = x3::int_ >> ('{' >> grammar % ',' >> '}' | x3::eps);
91 BOOST_SPIRIT_DEFINE(grammar)
92
93 BOOST_SPIRIT_INSTANTIATE(decltype(grammar), char const*, x3::unused_type)
94
95 }
96
97
main()98 int main()
99 {
100 using spirit_test::test_attr;
101 using spirit_test::test;
102
103 using namespace boost::spirit::x3::ascii;
104 using boost::spirit::x3::rule;
105 using boost::spirit::x3::lit;
106 using boost::spirit::x3::eps;
107 using boost::spirit::x3::unused_type;
108
109
110 { // synth attribute value-init
111
112 std::string s;
113 typedef rule<class r, std::string> rule_type;
114
115 auto rdef = rule_type()
116 = alpha [f()]
117 ;
118
119 BOOST_TEST(test_attr("abcdef", +rdef, s));
120 BOOST_TEST(s == "abcdef");
121 }
122
123 { // synth attribute value-init
124
125 std::string s;
126 typedef rule<class r, std::string> rule_type;
127
128 auto rdef = rule_type() =
129 alpha /
130 [](auto& ctx)
131 {
132 _val(ctx) += _attr(ctx);
133 }
134 ;
135
136 BOOST_TEST(test_attr("abcdef", +rdef, s));
137 BOOST_TEST(s == "abcdef");
138 }
139
140 {
141 auto r = rule<class r, int>{} = eps[([] (auto& ctx) {
142 using boost::spirit::x3::_val;
143 static_assert(std::is_same<std::decay_t<decltype(_val(ctx))>, unused_type>::value,
144 "Attribute must not be synthesized");
145 })];
146 BOOST_TEST(test("", r));
147 }
148
149 { // ensure no unneeded synthesization, copying and moving occurred
150 stationary st { 0 };
151 BOOST_TEST(test_attr("{42}", check_stationary::b, st));
152 BOOST_TEST_EQ(st.val, 42);
153 }
154
155 {
156 using namespace check_recursive;
157 node_t v;
158 BOOST_TEST(test_attr("[4,2]", grammar, v));
159 BOOST_TEST((node_t{std::vector<node_t>{{4}, {2}}} == v));
160 }
161 {
162 using namespace check_recursive_scoped;
163 node_t v;
164 BOOST_TEST(test_attr("[4,2]", grammar, v));
165 BOOST_TEST((node_t{std::vector<node_t>{{4}, {2}}} == v));
166 }
167
168 return boost::report_errors();
169 }
170