1 /*=============================================================================
2 Copyright (c) 2003 Giovanni Bajo
3 http://spirit.sourceforge.net/
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #include <boost/spirit/include/classic_core.hpp>
10 #include <boost/spirit/include/classic_ast.hpp>
11 #include <boost/spirit/include/classic_tree_to_xml.hpp>
12 #include <boost/preprocessor/arithmetic/inc.hpp>
13 #include <boost/preprocessor/punctuation/comma_if.hpp>
14 #include <boost/preprocessor/repetition.hpp>
15 #include <boost/preprocessor/arithmetic/sub.hpp>
16 #include <boost/mpl/list.hpp>
17 #include <boost/mpl/apply.hpp>
18 #include <boost/mpl/remove.hpp>
19 #include <boost/mpl/size.hpp>
20 #include <boost/mpl/for_each.hpp>
26 #include <boost/core/lightweight_test.hpp>
27 #include "impl/string_length.hpp"
29 #define DEBUG_DUMP_TREES (1)
31 //////////////////////////////////////////////////////////////////////////////
33 // http://sf.net/tracker/index.php?func=detail&aid=715483&group_id=28447&atid=393389)
35 namespace boost
{ namespace spirit
{
40 typename ContextT
= parser_context
<> >
42 : public rule
<ScannerT
, ContextT
, parser_tag
<ID
> >
44 typedef rule
<ScannerT
, ContextT
, parser_tag
<ID
> > base_t
;
47 // Forward ctors and operator=.
56 rule_id
& operator=(const T
& a
)
57 { base_t::operator=(a
); return *this; }
62 //////////////////////////////////////////////////////////////////////////////
65 namespace mpl
= boost::mpl
;
66 using namespace BOOST_SPIRIT_CLASSIC_NS
;
78 map
<parser_id
, string
> rule_names
;
81 //////////////////////////////////////////////////////////////////////////////
82 // Generic tree manipulation tools
84 template <typename TreeT
>
86 { return (RULE_ID
)t
.value
.id().to_long(); }
89 template <typename TreeT
>
90 TreeT
& child(TreeT
& t
, unsigned n
)
95 template <typename TreeT
>
96 size_t num_children(const TreeT
& t
)
97 { return t
.children
.size(); }
99 template <typename TreeT
>
100 typename
TreeT::parse_node_t::iterator_t
ValueBeginIterator(TreeT
& t
)
101 { return t
.value
.begin(); }
103 template <typename TreeT
>
104 typename
TreeT::parse_node_t::iterator_t
ValueEndIterator(TreeT
& t
)
105 { return t
.value
.end(); }
107 template <typename TreeT
>
108 bool equal(TreeT
& a
, TreeT
& b
)
113 if (num_children(a
) != num_children(b
))
116 unsigned n
= num_children(a
);
117 for (unsigned i
=0;i
<n
;i
++)
118 if (!equal(child(a
, i
), child(b
, i
)))
124 template <typename TreeT
>
125 void dump(ostream
& o
, TreeT
& t
, int level
= 0)
129 map
<parser_id
, string
>::iterator iter
=
130 rule_names
.find(id(t
));
132 if (iter
== rule_names
.end())
137 value
.assign(ValueBeginIterator(t
), ValueEndIterator(t
));
139 for (int i
=0;i
<level
;i
++)
143 o
<< name
<< ": " << value
<< endl
;
145 unsigned n
= num_children(t
);
146 for (unsigned c
=0;c
<n
;c
++)
147 dump(o
, child(t
, c
), level
+1);
151 //////////////////////////////////////////////////////////////////////////////
154 namespace test_impl
{
156 template <typename ParmT
>
160 void operator()(ParmT
& t
, ParmT ch
) const
163 // wrong specialization
164 template <typename TreeT
>
165 void operator()(TreeT
& t
, ParmT p
) const
166 { typedef typename
TreeT::this_should_never_be_compiled type
; }
170 struct fold_node
<nil_t
>
172 template <typename TreeT
>
173 void operator()(TreeT
& t
, nil_t
) const
174 { typedef typename
TreeT::this_should_never_be_compiled type
; }
178 struct fold_node
<RULE_ID
>
180 template <typename TreeT
>
181 void operator()(TreeT
& t
, RULE_ID id
) const
185 template <typename ParmT
>
188 template <typename TreeT
>
189 void operator()(TreeT
& t
, ParmT p
, unsigned n
) const
190 { fold_node
<ParmT
>()(t
.children
[n
], p
); }
194 struct fold_child
<nil_t
>
196 template <typename TreeT
>
197 void operator()(TreeT
& t
, nil_t
, unsigned n
) const
202 template <typename TreeT
,
203 typename T
, typename T1
, typename T2
, typename T3
, typename T4
,
204 typename T5
, typename T6
, typename T7
, typename T8
>
205 TreeT
fold(T p
, T1 p1
, T2 p2
, T3 p3
, T4 p4
, T5 p5
, T6 p6
, T7 p7
, T8 p8
)
207 // Prepare a list with all the template types
208 typedef mpl::list
<T1
,T2
,T3
,T4
,T5
,T6
,T7
,T8
> full_list_t
;
210 // Remove the ones equal to nil_t: they are the default parameters
211 // unspecified from the user
212 typedef typename
mpl::remove
<full_list_t
, nil_t
>::type parm_list_t
;
214 // Get the size of the list = number of parameters specified by the user
215 typedef typename
mpl::size
<parm_list_t
>::type parm_list_size_t
;
216 enum { NUM_CHILDREN
= parm_list_size_t::value
};
220 // Generate the root of the tree (specialized for the first parameter)
221 test_impl::fold_node
<T
>()(t
, p
);
223 // Make room for the children
224 if (NUM_CHILDREN
> 0)
225 t
.children
.resize(NUM_CHILDREN
);
227 // For each children, call the GenerateChild function, which is specialized
228 // on the different types
229 test_impl::fold_child
<T1
>()(t
, p1
, 0);
230 test_impl::fold_child
<T2
>()(t
, p2
, 1);
231 test_impl::fold_child
<T3
>()(t
, p3
, 2);
232 test_impl::fold_child
<T4
>()(t
, p4
, 3);
233 test_impl::fold_child
<T5
>()(t
, p5
, 4);
234 test_impl::fold_child
<T6
>()(t
, p6
, 5);
235 test_impl::fold_child
<T7
>()(t
, p7
, 6);
236 test_impl::fold_child
<T8
>()(t
, p8
, 7);
242 // Define fold() wrapper for 1->7 parameters: they just call the 8 parameter
243 // version passing nil_t for the other arguments
244 #define PUT_EMPTY(Z, N, _) nil_t()
246 #define DEFINE_FOLD(Z, N, _) \
247 template <typename TreeT, typename T BOOST_PP_COMMA_IF(N) \
248 BOOST_PP_ENUM_PARAMS(N, typename T) > \
249 TreeT fold(T p BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS(N, T, p)) \
251 return fold<TreeT>(p \
252 BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, p) \
253 BOOST_PP_COMMA_IF(BOOST_PP_SUB(8,N)) \
254 BOOST_PP_ENUM(BOOST_PP_SUB(8,N), PUT_EMPTY, _)); \
257 BOOST_PP_REPEAT(7, DEFINE_FOLD
, _
)
264 //////////////////////////////////////////////////////////////////////////////
265 // test_banal: simple tree construction
267 struct test_banal
: public grammar
<test_banal
>
272 rule_id
<T
, ID_ROOT
> root
;
277 definition(const test_banal
&)
285 const rule_id
<T
, ID_ROOT
>& start()
289 const char* pattern(void)
294 template <typename TreeT
>
295 TreeT
expected_tree(void)
298 ID_ROOT
, fold
<TreeT
>(
306 //////////////////////////////////////////////////////////////////////////////
316 //////////////////////////////////////////////////////////////////////////////
317 // run_test - code to run a test
321 template <typename TestT
>
322 void operator()(TestT gram
)
324 typedef const char* iterator_t
;
325 typedef node_val_data_factory
<nil_t
> factory_t
;
328 ::BOOST_NESTED_TEMPLATE factory
<iterator_t
>
330 typedef tree_node
<node_t
> tree_t
;
332 iterator_t text_begin
= gram
.pattern();
333 iterator_t text_end
= text_begin
+ test_impl::string_length(text_begin
);
335 tree_parse_info
<iterator_t
, factory_t
> info
=
336 ast_parse(text_begin
, text_end
, gram
);
338 BOOST_TEST(info
.full
);
340 tree_t expected
= gram
.template expected_tree
<tree_t
>();
343 dump(cout
, info
.trees
[0]);
344 dump(cout
, expected
);
347 BOOST_TEST(equal(info
.trees
[0], expected
));
351 //////////////////////////////////////////////////////////////////////////////
354 #ifdef BOOST_NO_EXCEPTIONS
357 void throw_exception(std::exception
const & )
359 std::cerr
<< "Exception caught" << std::endl
;
369 rule_names
[ID_ROOT
] = "ID_ROOT";
370 rule_names
[ID_A
] = "ID_A";
371 rule_names
[ID_B
] = "ID_B";
372 rule_names
[ID_C
] = "ID_C";
380 mpl::for_each
<tests_t
, mpl::_
> (run_test());
382 return boost::report_errors();