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#ifndef BOOST_SPIRIT_QI_ACTION_ACTION_HPP
8#define BOOST_SPIRIT_QI_ACTION_ACTION_HPP
9
10#if defined(_MSC_VER)
11#pragma once
12#endif
13
14#include <boost/spirit/home/qi/meta_compiler.hpp>
15#include <boost/spirit/home/qi/parser.hpp>
16#include <boost/spirit/home/qi/detail/attributes.hpp>
17#include <boost/spirit/home/support/argument.hpp>
18#include <boost/spirit/home/support/context.hpp>
19#include <boost/spirit/home/support/unused.hpp>
20#include <boost/spirit/home/support/info.hpp>
21#include <boost/spirit/home/support/action_dispatch.hpp>
22#include <boost/spirit/home/support/handles_container.hpp>
23
24#include <boost/mpl/bool.hpp>
25#include <boost/mpl/if.hpp>
26#include <boost/type_traits/remove_const.hpp>
27#include <boost/type_traits/is_same.hpp>
28
29namespace boost { namespace spirit { namespace qi
30{
31 BOOST_PP_REPEAT(SPIRIT_ARGUMENTS_LIMIT, SPIRIT_USING_ARGUMENT, _)
32
33 template <typename Subject, typename Action>
34 struct action : unary_parser<action<Subject, Action> >
35 {
36 typedef Subject subject_type;
37 typedef Action action_type;
38
39 template <typename Context, typename Iterator>
40 struct attribute
41 : traits::attribute_of<Subject, Context, Iterator>
42 {};
43
44 action(Subject const& subject_, Action f_)
45 : subject(subject_), f(f_) {}
46
47#ifndef BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT
48 template <typename Iterator, typename Context
49 , typename Skipper, typename Attribute>
50 bool parse(Iterator& first, Iterator const& last
51 , Context& context, Skipper const& skipper
52 , Attribute& attr_) const
53 {
54 typedef typename attribute<Context, Iterator>::type attr_type;
55
56 // create an attribute if one is not supplied
57 typedef traits::transform_attribute<
58 Attribute, attr_type, domain> transform;
59
60 typename transform::type attr = transform::pre(attr_);
61
62 Iterator save = first;
63 if (subject.parse(first, last, context, skipper, attr))
64 {
65 // call the function, passing the attribute, the context.
66 // The client can return false to fail parsing.
67 if (traits::action_dispatch<Subject>()(f, attr, context))
68 {
69 // Do up-stream transformation, this integrates the results
70 // back into the original attribute value, if appropriate.
71 transform::post(attr_, attr);
72 return true;
73 }
74
75 // reset iterators if semantic action failed the match
76 // retrospectively
77 first = save;
78 }
79 return false;
80 }
81#else
82 template <typename Iterator, typename Context
83 , typename Skipper, typename Attribute>
84 bool parse(Iterator& first, Iterator const& last
85 , Context& context, Skipper const& skipper
86 , Attribute& attr) const
87 {
88 Iterator save = first;
89 if (subject.parse(first, last, context, skipper, attr)) // Use the attribute as-is
90 {
91 // call the function, passing the attribute, the context.
92 // The client can return false to fail parsing.
93 if (traits::action_dispatch<Subject>()(f, attr, context))
94 return true;
95
96 // reset iterators if semantic action failed the match
97 // retrospectively
98 first = save;
99 }
100 return false;
101 }
102
103 template <typename Iterator, typename Context
104 , typename Skipper>
105 bool parse(Iterator& first, Iterator const& last
106 , Context& context, Skipper const& skipper
107 , unused_type) const
108 {
109 typedef typename attribute<Context, Iterator>::type attr_type;
110
111 // synthesize the attribute since one is not supplied
112 attr_type attr = attr_type();
113
114 Iterator save = first;
115 if (subject.parse(first, last, context, skipper, attr))
116 {
117 // call the function, passing the attribute, the context.
118 // The client can return false to fail parsing.
119 if (traits::action_dispatch<Subject>()(f, attr, context))
120 return true;
121
122 // reset iterators if semantic action failed the match
123 // retrospectively
124 first = save;
125 }
126 return false;
127 }
128#endif
129
130 template <typename Context>
131 info what(Context& context) const
132 {
133 // the action is transparent (does not add any info)
134 return subject.what(context);
135 }
136
137 Subject subject;
138 Action f;
139 };
140}}}
141
142namespace boost { namespace spirit
143{
144 // Qi action meta-compiler
145 template <>
146 struct make_component<qi::domain, tag::action>
147 {
148 template <typename Sig>
149 struct result;
150
151 template <typename This, typename Elements, typename Modifiers>
152 struct result<This(Elements, Modifiers)>
153 {
154 typedef typename
155 remove_const<typename Elements::car_type>::type
156 subject_type;
157
158 typedef typename
159 remove_const<typename Elements::cdr_type::car_type>::type
160 action_type;
161
162 typedef qi::action<subject_type, action_type> type;
163 };
164
165 template <typename Elements>
166 typename result<make_component(Elements, unused_type)>::type
167 operator()(Elements const& elements, unused_type) const
168 {
169 typename result<make_component(Elements, unused_type)>::type
170 result(elements.car, elements.cdr.car);
171 return result;
172 }
173 };
174}}
175
176namespace boost { namespace spirit { namespace traits
177{
178 ///////////////////////////////////////////////////////////////////////////
179 template <typename Subject, typename Action>
180 struct has_semantic_action<qi::action<Subject, Action> >
181 : mpl::true_ {};
182
183 ///////////////////////////////////////////////////////////////////////////
184 template <typename Subject, typename Action, typename Attribute
185 , typename Context, typename Iterator>
186 struct handles_container<qi::action<Subject, Action>, Attribute
187 , Context, Iterator>
188 : unary_handles_container<Subject, Attribute, Context, Iterator> {};
189}}}
190
191#endif
192

source code of boost/libs/spirit/include/boost/spirit/home/qi/action/action.hpp