1 /*=============================================================================
2     Copyright (c) 2003 Giovanni Bajo
3     http://spirit.sourceforge.net/
4 
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>
21 
22 #include <map>
23 #include <string>
24 
25 #include <fstream>
26 #include <boost/detail/lightweight_test.hpp>
27 #include "impl/string_length.hpp"
28 
29 #define DEBUG_DUMP_TREES    (1)
30 
31 //////////////////////////////////////////////////////////////////////////////
32 // rule_id helper
33 // http://sf.net/tracker/index.php?func=detail&aid=715483&group_id=28447&atid=393389)
34 
35 namespace boost { namespace spirit {
36 
37     template <
38         typename ScannerT,
39         unsigned long ID = 0,
40         typename ContextT = parser_context<> >
41     class rule_id
42         : public rule<ScannerT, ContextT, parser_tag<ID> >
43     {
44         typedef rule<ScannerT, ContextT, parser_tag<ID> > base_t;
45 
46     public:
47         // Forward ctors and operator=.
rule_id()48         rule_id()
49         {}
50 
51         template <typename T>
rule_id(const T & a)52         rule_id(const T& a)
53         : base_t(a) {}
54 
55         template <typename T>
operator =(const T & a)56         rule_id& operator=(const T& a)
57         { base_t::operator=(a); return *this; }
58     };
59 }}
60 
61 
62 //////////////////////////////////////////////////////////////////////////////
63 // Framework setup
64 
65 namespace mpl = boost::mpl;
66 using namespace BOOST_SPIRIT_CLASSIC_NS;
67 using namespace std;
68 
69 
70 enum RULE_ID
71 {
72     ID_A = 1,
73     ID_B,
74     ID_C,
75     ID_ROOT
76 };
77 
78 map<parser_id, string> rule_names;
79 
80 
81 //////////////////////////////////////////////////////////////////////////////
82 // Generic tree manipulation tools
83 
84 template <typename TreeT>
id(TreeT & t)85 RULE_ID id(TreeT& t)
86 { return (RULE_ID)t.value.id().to_long(); }
87 
88 
89 template <typename TreeT>
child(TreeT & t,unsigned n)90 TreeT& child(TreeT& t, unsigned n)
91 {
92     return t.children[n];
93 }
94 
95 template <typename TreeT>
num_children(const TreeT & t)96 size_t num_children(const TreeT& t)
97 { return t.children.size(); }
98 
99 template <typename TreeT>
ValueBeginIterator(TreeT & t)100 typename TreeT::parse_node_t::iterator_t ValueBeginIterator(TreeT& t)
101 { return t.value.begin(); }
102 
103 template <typename TreeT>
ValueEndIterator(TreeT & t)104 typename TreeT::parse_node_t::iterator_t ValueEndIterator(TreeT& t)
105 { return t.value.end(); }
106 
107 template <typename TreeT>
equal(TreeT & a,TreeT & b)108 bool equal(TreeT& a, TreeT& b)
109 {
110     if (id(a) != id(b))
111         return false;
112 
113     if (num_children(a) != num_children(b))
114         return false;
115 
116     unsigned n = num_children(a);
117     for (unsigned i=0;i<n;i++)
118         if (!equal(child(a, i), child(b, i)))
119             return false;
120 
121     return true;
122 }
123 
124 template <typename TreeT>
dump(ostream & o,TreeT & t,int level=0)125 void dump(ostream& o, TreeT& t, int level = 0)
126 {
127     string name;
128     string value;
129     map<parser_id, string>::iterator iter =
130         rule_names.find(id(t));
131 
132     if (iter == rule_names.end())
133         name = "noname";
134     else
135         name = iter->second;
136 
137     value.assign(ValueBeginIterator(t), ValueEndIterator(t));
138 
139     for (int i=0;i<level;i++)
140         o << "  ";
141 
142 
143     o << name << ": " << value << endl;
144 
145     unsigned n = num_children(t);
146     for (unsigned c=0;c<n;c++)
147         dump(o, child(t, c), level+1);
148 }
149 
150 
151 //////////////////////////////////////////////////////////////////////////////
152 // Tree folding
153 
154 namespace test_impl {
155 
156     template <typename ParmT>
157     struct fold_node
158     {
159         // assign a subtree
operator ()test_impl::fold_node160         void operator()(ParmT& t, ParmT ch) const
161         { t = ch; }
162 
163         // wrong specialization
164         template <typename TreeT>
operator ()test_impl::fold_node165         void operator()(TreeT& t, ParmT p) const
166         { typedef typename TreeT::this_should_never_be_compiled type; }
167     };
168 
169     template <>
170     struct fold_node<nil_t>
171     {
172         template <typename TreeT>
operator ()test_impl::fold_node173         void operator()(TreeT& t, nil_t) const
174         { typedef typename TreeT::this_should_never_be_compiled type; }
175     };
176 
177     template <>
178     struct fold_node<RULE_ID>
179     {
180         template <typename TreeT>
operator ()test_impl::fold_node181         void operator()(TreeT& t, RULE_ID id) const
182         { t.value.id(id); }
183     };
184 
185     template <typename ParmT>
186     struct fold_child
187     {
188         template <typename TreeT>
operator ()test_impl::fold_child189         void operator()(TreeT& t, ParmT p, unsigned n) const
190         { fold_node<ParmT>()(t.children[n], p); }
191     };
192 
193     template <>
194     struct fold_child<nil_t>
195     {
196         template <typename TreeT>
operator ()test_impl::fold_child197         void operator()(TreeT& t, nil_t, unsigned n) const
198         {}
199     };
200 }
201 
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)
206 {
207     // Prepare a list with all the template types
208     typedef mpl::list<T1,T2,T3,T4,T5,T6,T7,T8> full_list_t;
209 
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;
213 
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 };
217 
218     TreeT t;
219 
220     // Generate the root of the tree (specialized for the first parameter)
221     test_impl::fold_node<T>()(t, p);
222 
223     // Make room for the children
224     if (NUM_CHILDREN > 0)
225         t.children.resize(NUM_CHILDREN);
226 
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);
237 
238     return t;
239 }
240 
241 
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()
245 
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)) \
250     { \
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, _)); \
255     }
256 
257 BOOST_PP_REPEAT(7, DEFINE_FOLD, _)
258 
259 #undef PUT_EMPTY
260 #undef DEFINE_FOLD
261 
262 
263 
264 //////////////////////////////////////////////////////////////////////////////
265 // test_banal: simple tree construction
266 
267 struct test_banal : public grammar<test_banal>
268 {
269     template <class T>
270     struct definition
271     {
272         rule_id<T, ID_ROOT> root;
273         rule_id<T, ID_A> a;
274         rule_id<T, ID_B> b;
275         rule_id<T, ID_C> c;
276 
definitiontest_banal::definition277         definition(const test_banal&)
278         {
279             root = a >> c;
280             a = b;
281             b = chlit<>('b');
282             c = chlit<>('c');
283         }
284 
starttest_banal::definition285         const rule_id<T, ID_ROOT>& start()
286         { return root; }
287     };
288 
patterntest_banal289     const char* pattern(void)
290     {
291         return "bc";
292     }
293 
294     template <typename TreeT>
expected_treetest_banal295     TreeT expected_tree(void)
296     {
297         return fold<TreeT>(
298             ID_ROOT, fold<TreeT>(
299                 ID_A,
300                     ID_B),
301                 ID_C);
302     }
303 };
304 
305 
306 //////////////////////////////////////////////////////////////////////////////
307 // All the tests
308 
309 typedef mpl::list
310 <
311     test_banal
312 
313 > tests_t;
314 
315 
316 //////////////////////////////////////////////////////////////////////////////
317 // run_test - code to run a test
318 
319 struct run_test
320 {
321     template <typename TestT>
operator ()run_test322     void operator()(TestT gram)
323     {
324         typedef const char* iterator_t;
325         typedef node_val_data_factory<nil_t> factory_t;
326         typedef typename
327             factory_t
328             ::BOOST_NESTED_TEMPLATE factory<iterator_t>
329             ::node_t node_t;
330         typedef tree_node<node_t> tree_t;
331 
332         iterator_t text_begin = gram.pattern();
333         iterator_t text_end = text_begin + test_impl::string_length(text_begin);
334 
335         tree_parse_info<iterator_t, factory_t> info =
336             ast_parse(text_begin, text_end, gram);
337 
338         BOOST_TEST(info.full);
339 
340         tree_t expected = gram.template expected_tree<tree_t>();
341 
342 #if DEBUG_DUMP_TREES
343         dump(cout, info.trees[0]);
344         dump(cout, expected);
345 #endif
346 
347         BOOST_TEST(equal(info.trees[0], expected));
348     }
349 };
350 
351 //////////////////////////////////////////////////////////////////////////////
352 // main() stuff
353 
354 #ifdef BOOST_NO_EXCEPTIONS
355 namespace boost
356 {
throw_exception(std::exception const &)357     void throw_exception(std::exception const & )
358     {
359         std::cerr << "Exception caught" << std::endl;
360         BOOST_TEST(0);
361     }
362 }
363 
364 #endif
365 
366 
init(void)367 void init(void)
368 {
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";
373 }
374 
375 
main()376 int main()
377 {
378     init();
379 
380     mpl::for_each<tests_t, mpl::_> (run_test());
381 
382     return boost::report_errors();
383 }
384