summaryrefslogtreecommitdiff
path: root/boost/spirit/home/qi/auxiliary/attr_cast.hpp
blob: 93d646c58d0f639f61dbc95175db9a0bb09c235a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//  Copyright (c) 2001-2011 Hartmut Kaiser
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(SPIRIT_QI_ATTR_CAST_SEP_26_2009_0735PM)
#define SPIRIT_QI_ATTR_CAST_SEP_26_2009_0735PM

#if defined(_MSC_VER)
#pragma once
#endif

#include <boost/spirit/home/qi/meta_compiler.hpp>
#include <boost/spirit/home/qi/parser.hpp>
#include <boost/spirit/home/qi/domain.hpp>
#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/info.hpp>
#include <boost/spirit/home/support/common_terminals.hpp>
#include <boost/spirit/home/qi/detail/attributes.hpp>
#include <boost/spirit/home/support/auxiliary/attr_cast.hpp>

namespace boost { namespace spirit
{
    ///////////////////////////////////////////////////////////////////////////
    // Enablers
    ///////////////////////////////////////////////////////////////////////////

    // enables attr_cast<>() pseudo parser
    template <typename Expr, typename Exposed, typename Transformed>
    struct use_terminal<qi::domain
          , tag::stateful_tag<Expr, tag::attr_cast, Exposed, Transformed> >
      : mpl::true_ {};
}}

namespace boost { namespace spirit { namespace qi
{
    using spirit::attr_cast;

    ///////////////////////////////////////////////////////////////////////////
    // attr_cast_parser consumes the attribute of subject generator without
    // generating anything
    ///////////////////////////////////////////////////////////////////////////
    template <typename Exposed, typename Transformed, typename Subject>
    struct attr_cast_parser 
      : unary_parser<attr_cast_parser<Exposed, Transformed, Subject> >
    {
        typedef typename result_of::compile<qi::domain, Subject>::type
            subject_type;

        typedef typename mpl::eval_if<
            traits::not_is_unused<Transformed>
          , mpl::identity<Transformed>
          , traits::attribute_of<subject_type> >::type
        transformed_attribute_type;

        attr_cast_parser(Subject const& subject_)
          : subject(subject_)
        {
            // If you got an error_invalid_expression error message here,
            // then the expression (Subject) is not a valid spirit qi
            // expression.
            BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Subject);
        }

        // If Exposed is given, we use the given type, otherwise all we can do
        // is to guess, so we expose our inner type as an attribute and
        // deal with the passed attribute inside the parse function.
        template <typename Context, typename Iterator>
        struct attribute
          : mpl::if_<traits::not_is_unused<Exposed>, Exposed
              , transformed_attribute_type>
        {};

        template <typename Iterator, typename Context, typename Skipper
          , typename Attribute>
        bool parse(Iterator& first, Iterator const& last
          , Context& context, Skipper const& skipper
          , Attribute& attr_param) const
        {
            // Find the real exposed attribute. If exposed is given, we use it
            // otherwise we assume the exposed attribute type to be the actual
            // attribute type as passed by the user.
            typedef typename mpl::if_<
                traits::not_is_unused<Exposed>, Exposed, Attribute>::type
            exposed_attribute_type;

            // do down-stream transformation, provides attribute for embedded
            // parser
            typedef traits::transform_attribute<
                exposed_attribute_type, transformed_attribute_type, domain>
            transform;

            typename transform::type attr_ = transform::pre(attr_param);

            if (!compile<qi::domain>(subject).
                    parse(first, last, context, skipper, attr_))
            {
                transform::fail(attr_param);
                return false;
            }

            // do up-stream transformation, this mainly integrates the results
            // back into the original attribute value, if appropriate
            traits::post_transform(attr_param, attr_);
            return true;
        }

        template <typename Context>
        info what(Context& context) const
        {
            return info("attr_cast"
              , compile<qi::domain>(subject).what(context));
        }

        Subject subject;

    private:
        // silence MSVC warning C4512: assignment operator could not be generated
        attr_cast_parser& operator= (attr_cast_parser const&);
    };

    ///////////////////////////////////////////////////////////////////////////
    // Parser generator: make_xxx function (objects)
    ///////////////////////////////////////////////////////////////////////////
    template <typename Expr, typename Exposed, typename Transformed
      , typename Modifiers>
    struct make_primitive<
        tag::stateful_tag<Expr, tag::attr_cast, Exposed, Transformed>, Modifiers>
    {
        typedef attr_cast_parser<Exposed, Transformed, Expr> result_type;

        template <typename Terminal>
        result_type operator()(Terminal const& term, unused_type) const
        {
            typedef tag::stateful_tag<
                Expr, tag::attr_cast, Exposed, Transformed> tag_type;
            using spirit::detail::get_stateful_data;
            return result_type(get_stateful_data<tag_type>::call(term));
        }
    };


}}}

#endif