1 /*=============================================================================
2     Copyright (c) 2001-2011 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 #if !defined(BOOST_SPIRIT_LAZY_MARCH_27_2007_1002AM)
8 #define BOOST_SPIRIT_LAZY_MARCH_27_2007_1002AM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/qi/domain.hpp>
15 #include <boost/spirit/home/qi/skip_over.hpp>
16 #include <boost/spirit/home/qi/meta_compiler.hpp>
17 #include <boost/spirit/home/qi/detail/attributes.hpp>
18 #include <boost/spirit/home/support/unused.hpp>
19 #include <boost/spirit/home/support/info.hpp>
20 #include <boost/spirit/home/support/lazy.hpp>
21 #include <boost/spirit/include/phoenix_core.hpp>
22 #include <boost/fusion/include/at.hpp>
23 #include <boost/utility/result_of.hpp>
24 #include <boost/type_traits/remove_reference.hpp>
25 #include <boost/mpl/not.hpp>
26 
27 namespace boost { namespace spirit
28 {
29     ///////////////////////////////////////////////////////////////////////////
30     // Enablers
31     ///////////////////////////////////////////////////////////////////////////
32     template <typename Eval>
33     struct use_terminal<qi::domain, phoenix::actor<Eval> >  // enables phoenix actors
34         : mpl::true_ {};
35 
36     // forward declaration
37     template <typename Terminal, typename Actor, int Arity>
38     struct lazy_terminal;
39 }}
40 
41 namespace boost { namespace spirit { namespace qi
42 {
43     using spirit::lazy;
44     typedef modify<qi::domain> qi_modify;
45 
46     namespace detail
47     {
48         template <typename Parser, typename Iterator, typename Context
49           , typename Skipper, typename Attribute>
lazy_parse_impl(Parser const & p,Iterator & first,Iterator const & last,Context & context,Skipper const & skipper,Attribute & attr,mpl::false_)50         bool lazy_parse_impl(Parser const& p
51           , Iterator& first, Iterator const& last
52           , Context& context, Skipper const& skipper
53           , Attribute& attr, mpl::false_)
54         {
55             return p.parse(first, last, context, skipper, attr);
56         }
57 
58         template <typename Parser, typename Iterator, typename Context
59           , typename Skipper, typename Attribute>
lazy_parse_impl(Parser const & p,Iterator & first,Iterator const & last,Context & context,Skipper const & skipper,Attribute &,mpl::true_)60         bool lazy_parse_impl(Parser const& p
61           , Iterator& first, Iterator const& last
62           , Context& context, Skipper const& skipper
63           , Attribute& /*attr*/, mpl::true_)
64         {
65             // If DeducedAuto is false (semantic actions is present), the
66             // component's attribute is unused.
67             return p.parse(first, last, context, skipper, unused);
68         }
69 
70         template <typename Parser, typename Iterator, typename Context
71           , typename Skipper, typename Attribute>
lazy_parse_impl_main(Parser const & p,Iterator & first,Iterator const & last,Context & context,Skipper const & skipper,Attribute & attr)72         bool lazy_parse_impl_main(Parser const& p
73           , Iterator& first, Iterator const& last
74           , Context& context, Skipper const& skipper
75           , Attribute& attr)
76         {
77             // If DeducedAuto is true (no semantic action), we pass the parser's
78             // attribute on to the component.
79             typedef typename traits::has_semantic_action<Parser>::type auto_rule;
80             return lazy_parse_impl(p, first, last, context, skipper, attr, auto_rule());
81         }
82     }
83 
84     template <typename Function, typename Modifiers>
85     struct lazy_parser : parser<lazy_parser<Function, Modifiers> >
86     {
87         template <typename Context, typename Iterator>
88         struct attribute
89         {
90             typedef typename
91                 boost::result_of<qi_modify(tag::lazy_eval, Modifiers)>::type
92             modifier;
93 
94             typedef typename
95                 remove_reference<
96                     typename boost::result_of<Function(unused_type, Context)>::type
97                 >::type
98             expr_type;
99 
100             // If you got an error_invalid_expression error message here,
101             // then the expression (expr_type) is not a valid spirit qi
102             // expression.
103             BOOST_SPIRIT_ASSERT_MATCH(qi::domain, expr_type);
104 
105             typedef typename
106                 result_of::compile<qi::domain, expr_type, modifier>::type
107             parser_type;
108 
109             typedef typename
110                 traits::attribute_of<parser_type, Context, Iterator>::type
111             type;
112         };
113 
lazy_parserboost::spirit::qi::lazy_parser114         lazy_parser(Function const& function_, Modifiers const& modifiers_)
115           : function(function_), modifiers(modifiers_) {}
116 
117         template <typename Iterator, typename Context
118           , typename Skipper, typename Attribute>
parseboost::spirit::qi::lazy_parser119         bool parse(Iterator& first, Iterator const& last
120           , Context& context, Skipper const& skipper
121           , Attribute& attr) const
122         {
123             return detail::lazy_parse_impl_main(
124                   compile<qi::domain>(function(unused, context)
125                 , qi_modify()(tag::lazy_eval(), modifiers))
126                 , first, last, context, skipper, attr);
127         }
128 
129         template <typename Context>
whatboost::spirit::qi::lazy_parser130         info what(Context& context) const
131         {
132             return info("lazy"
133               , compile<qi::domain>(function(unused, context)
134                 , qi_modify()(tag::lazy_eval(), modifiers))
135                     .what(context)
136             );
137         }
138 
139         Function function;
140         Modifiers modifiers;
141     };
142 
143 
144     template <typename Function, typename Subject, typename Modifiers>
145     struct lazy_directive
146         : unary_parser<lazy_directive<Function, Subject, Modifiers> >
147     {
148         typedef Subject subject_type;
149 
150         template <typename Context, typename Iterator>
151         struct attribute
152         {
153             typedef typename
154                 boost::result_of<qi_modify(tag::lazy_eval, Modifiers)>::type
155             modifier;
156 
157             typedef typename
158                 remove_reference<
159                     typename boost::result_of<Function(unused_type, Context)>::type
160                 >::type
161             directive_expr_type;
162 
163             typedef typename
164                 proto::result_of::make_expr<
165                     proto::tag::subscript
166                   , directive_expr_type
167                   , Subject
168                 >::type
169             expr_type;
170 
171             // If you got an error_invalid_expression error message here,
172             // then the expression (expr_type) is not a valid spirit qi
173             // expression.
174             BOOST_SPIRIT_ASSERT_MATCH(qi::domain, expr_type);
175 
176             typedef typename
177                 result_of::compile<qi::domain, expr_type, modifier>::type
178             parser_type;
179 
180             typedef typename
181                 traits::attribute_of<parser_type, Context, Iterator>::type
182             type;
183         };
184 
lazy_directiveboost::spirit::qi::lazy_directive185         lazy_directive(
186             Function const& function_
187           , Subject const& subject_
188           , Modifiers const& modifiers_)
189           : function(function_), subject(subject_), modifiers(modifiers_) {}
190 
191         template <typename Iterator, typename Context
192           , typename Skipper, typename Attribute>
parseboost::spirit::qi::lazy_directive193         bool parse(Iterator& first, Iterator const& last
194           , Context& context, Skipper const& skipper
195           , Attribute& attr) const
196         {
197             return detail::lazy_parse_impl_main(compile<qi::domain>(
198                 proto::make_expr<proto::tag::subscript>(
199                     function(unused, context)
200                   , subject)
201                 , qi_modify()(tag::lazy_eval(), modifiers))
202                 , first, last, context, skipper, attr);
203         }
204 
205         template <typename Context>
whatboost::spirit::qi::lazy_directive206         info what(Context& context) const
207         {
208             return info("lazy-directive"
209               , compile<qi::domain>(
210                     proto::make_expr<proto::tag::subscript>(
211                         function(unused, context)
212                       , subject
213                     ), qi_modify()(tag::lazy_eval(), modifiers))
214                     .what(context)
215             );
216         }
217 
218         Function function;
219         Subject subject;
220         Modifiers modifiers;
221     };
222 
223     ///////////////////////////////////////////////////////////////////////////
224     // Parser generators: make_xxx function (objects)
225     ///////////////////////////////////////////////////////////////////////////
226     template <typename Eval, typename Modifiers>
227     struct make_primitive<phoenix::actor<Eval>, Modifiers>
228     {
229         typedef lazy_parser<phoenix::actor<Eval>, Modifiers> result_type;
operator ()boost::spirit::qi::make_primitive230         result_type operator()(phoenix::actor<Eval> const& f
231           , Modifiers const& modifiers) const
232         {
233             return result_type(f, modifiers);
234         }
235     };
236 
237     template <typename Terminal, typename Actor, int Arity, typename Modifiers>
238     struct make_primitive<lazy_terminal<Terminal, Actor, Arity>, Modifiers>
239     {
240         typedef lazy_parser<Actor, Modifiers> result_type;
operator ()boost::spirit::qi::make_primitive241         result_type operator()(
242             lazy_terminal<Terminal, Actor, Arity> const& lt
243           , Modifiers const& modifiers) const
244         {
245             return result_type(lt.actor, modifiers);
246         }
247     };
248 
249     template <typename Terminal, typename Actor, int Arity, typename Subject, typename Modifiers>
250     struct make_directive<lazy_terminal<Terminal, Actor, Arity>, Subject, Modifiers>
251     {
252         typedef lazy_directive<Actor, Subject, Modifiers> result_type;
operator ()boost::spirit::qi::make_directive253         result_type operator()(
254             lazy_terminal<Terminal, Actor, Arity> const& lt
255           , Subject const& subject, Modifiers const& modifiers) const
256         {
257             return result_type(lt.actor, subject, modifiers);
258         }
259     };
260 }}}
261 
262 namespace boost { namespace spirit { namespace traits
263 {
264     ///////////////////////////////////////////////////////////////////////////
265     template <typename Actor, typename Modifiers, typename Attribute
266       , typename Context, typename Iterator>
267     struct handles_container<
268         qi::lazy_parser<Actor, Modifiers>, Attribute, Context, Iterator>
269       : handles_container<
270           typename qi::lazy_parser<Actor, Modifiers>::template
271               attribute<Context, Iterator>::parser_type
272         , Attribute, Context, Iterator>
273     {};
274 
275     template <typename Subject, typename Actor, typename Modifiers
276       , typename Attribute, typename Context, typename Iterator>
277     struct handles_container<
278         qi::lazy_directive<Actor, Subject, Modifiers>, Attribute
279       , Context, Iterator>
280       : handles_container<
281           typename qi::lazy_directive<Actor, Subject, Modifiers>::template
282               attribute<Context, Iterator>::parser_type
283         , Attribute, Context, Iterator>
284     {};
285 }}}
286 
287 #endif
288