1 //  Copyright (c) 2001-2011 Joel de Guzman
2 //  Copyright (c) 2001-2011 Hartmut Kaiser
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 #if !defined(BOOST_SPIRIT_KARMA_GRAMMAR_MAR_05_2007_0542PM)
8 #define BOOST_SPIRIT_KARMA_GRAMMAR_MAR_05_2007_0542PM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/support/unused.hpp>
15 #include <boost/spirit/home/support/info.hpp>
16 #include <boost/spirit/home/support/assert_msg.hpp>
17 #include <boost/spirit/home/karma/domain.hpp>
18 #include <boost/spirit/home/karma/nonterminal/rule.hpp>
19 #include <boost/spirit/home/karma/nonterminal/nonterminal_fwd.hpp>
20 #include <boost/spirit/home/karma/reference.hpp>
21 #include <boost/noncopyable.hpp>
22 #include <boost/proto/extends.hpp>
23 #include <boost/proto/traits.hpp>
24 #include <boost/type_traits/is_same.hpp>
25 
26 namespace boost { namespace spirit { namespace karma
27 {
28     template <
29         typename OutputIterator, typename T1, typename T2, typename T3
30       , typename T4>
31     struct grammar
32       : proto::extends<
33             typename proto::terminal<
34                 reference<rule<OutputIterator, T1, T2, T3, T4> const>
35             >::type
36           , grammar<OutputIterator, T1, T2, T3, T4>
37         >
38       , generator<grammar<OutputIterator, T1, T2, T3, T4> >
39       , noncopyable
40     {
41         typedef OutputIterator iterator_type;
42         typedef rule<OutputIterator, T1, T2, T3, T4> start_type;
43         typedef typename start_type::properties properties;
44         typedef typename start_type::sig_type sig_type;
45         typedef typename start_type::locals_type locals_type;
46         typedef typename start_type::delimiter_type delimiter_type;
47         typedef typename start_type::encoding_type encoding_type;
48         typedef grammar<OutputIterator, T1, T2, T3, T4> base_type;
49         typedef reference<start_type const> reference_;
50         typedef typename proto::terminal<reference_>::type terminal;
51 
52         static size_t const params_size = start_type::params_size;
53 
54         template <typename Context, typename Unused>
55         struct attribute
56         {
57             typedef typename start_type::attr_type type;
58         };
59 
60         // the output iterator is always wrapped by karma
61         typedef detail::output_iterator<OutputIterator, properties>
62             output_iterator;
63 
grammarboost::spirit::karma::grammar64         grammar(start_type const& start
65               , std::string const& name_ = "unnamed-grammar")
66           : proto::extends<terminal, base_type>(terminal::make(reference_(start)))
67           , name_(name_)
68         {}
69 
70         // This constructor is used to catch if the start rule is not
71         // compatible with the grammar.
72         template <typename Iterator_, typename T1_, typename T2_, typename T3_,
73             typename T4_>
grammarboost::spirit::karma::grammar74         grammar(rule<Iterator_, T1_, T2_, T3_, T4_> const&
75               , std::string const& = "unnamed-grammar")
76         {
77             // If you see the assertion below failing then the start rule
78             // passed to the constructor of the grammar is not compatible with
79             // the grammar (i.e. it uses different template parameters).
80             BOOST_SPIRIT_ASSERT_MSG(
81                 (is_same<start_type, rule<Iterator_, T1_, T2_, T3_, T4_> >::value)
82               , incompatible_start_rule, (rule<Iterator_, T1_, T2_, T3_, T4_>));
83         }
84 
nameboost::spirit::karma::grammar85         std::string name() const
86         {
87             return name_;
88         }
89 
nameboost::spirit::karma::grammar90         void name(std::string const& str)
91         {
92             name_ = str;
93         }
94 
95         template <typename Context, typename Delimiter, typename Attribute>
generateboost::spirit::karma::grammar96         bool generate(output_iterator& sink, Context& context
97           , Delimiter const& delim, Attribute const& attr) const
98         {
99             return this->proto_base().child0.generate(
100                 sink, context, delim, attr);
101         }
102 
103         template <typename Context>
whatboost::spirit::karma::grammar104         info what(Context&) const
105         {
106             return info(name_);
107         }
108 
109         // bring in the operator() overloads
get_parameterized_subjectboost::spirit::karma::grammar110         start_type const& get_parameterized_subject() const
111         { return this->proto_base().child0.ref.get(); }
112         typedef start_type parameterized_subject_type;
113         #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp>
114 
115         std::string name_;
116     };
117 }}}
118 
119 namespace boost { namespace spirit { namespace traits
120 {
121     ///////////////////////////////////////////////////////////////////////////
122     template <
123         typename IteratorA, typename IteratorB, typename Attribute
124       , typename Context, typename T1, typename T2, typename T3, typename T4>
125     struct handles_container<
126             karma::grammar<IteratorA, T1, T2, T3, T4>, Attribute, Context
127           , IteratorB>
128       : detail::nonterminal_handles_container<
129             typename attribute_of<
130                 karma::grammar<IteratorA, T1, T2, T3, T4>
131               , Context, IteratorB
132           >::type, Attribute>
133     {};
134 }}}
135 
136 #endif
137