Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/spirit/test/tree_tests.cpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 9.3 KB
Line 
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/core.hpp>
10#include <boost/spirit/tree/ast.hpp>
11#include <boost/spirit/tree/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
35namespace 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=.
48        rule_id()
49        {}
50
51        template <typename T>
52        rule_id(const T& a) 
53        : base_t(a) {}
54
55        template <typename T>
56        rule_id& operator=(const T& a)
57        { base_t::operator=(a); return *this; }
58    };
59}}
60
61
62//////////////////////////////////////////////////////////////////////////////
63// Framework setup
64
65namespace mpl = boost::mpl;
66using namespace boost::spirit;
67using namespace std;
68
69
70enum RULE_ID
71{
72    ID_A = 1,
73    ID_B,
74    ID_C,
75    ID_ROOT
76};
77
78map<parser_id, string> rule_names;
79
80
81//////////////////////////////////////////////////////////////////////////////
82// Generic tree manipulation tools
83
84template <typename TreeT>
85RULE_ID id(TreeT& t)
86{ return (RULE_ID)t.value.id().to_long(); }
87
88
89template <typename TreeT>
90TreeT& child(TreeT& t, unsigned n)
91{
92    return t.children[n];
93}
94
95template <typename TreeT>
96size_t num_children(const TreeT& t)
97{ return t.children.size(); }
98
99template <typename TreeT>
100typename TreeT::parse_node_t::iterator_t ValueBeginIterator(TreeT& t)
101{ return t.value.begin(); }
102
103template <typename TreeT>
104typename TreeT::parse_node_t::iterator_t ValueEndIterator(TreeT& t)
105{ return t.value.end(); }
106
107template <typename TreeT>
108bool 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
124template <typename TreeT>
125void 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
154namespace test_impl {
155
156    template <typename ParmT>
157    struct fold_node
158    {
159        // assign a subtree
160        void operator()(ParmT& t, ParmT ch) const
161        { t = ch; }
162
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; }
167    };
168
169    template <>
170    struct fold_node<nil_t>
171    {
172        template <typename TreeT>
173        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>
181        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>
189        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>
197        void operator()(TreeT& t, nil_t, unsigned n) const
198        {}
199    };
200}
201
202template <typename TreeT,
203        typename T, typename T1, typename T2, typename T3, typename T4,
204        typename T5, typename T6, typename T7, typename T8>
205TreeT 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
257BOOST_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
267struct 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
277        definition(const test_banal&)
278        {
279            root = a >> c;
280            a = b;
281            b = chlit<>('b');
282            c = chlit<>('c');
283        }
284
285        const rule_id<T, ID_ROOT>& start() 
286        { return root; }
287    };
288
289    const char* pattern(void)
290    {
291        return "bc";
292    }
293
294    template <typename TreeT>
295    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
309typedef mpl::list
310<
311    test_banal
312
313> tests_t;
314
315
316//////////////////////////////////////////////////////////////////////////////
317// run_test - code to run a test
318
319struct run_test
320{
321    template <typename TestT>
322    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
355namespace boost
356{
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
367void 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
376int main()
377{
378    init();
379
380    mpl::for_each<tests_t, mpl::_> (run_test());
381
382    return boost::report_errors();
383}
Note: See TracBrowser for help on using the repository browser.