Ticket #6050: spirit-transform-attribute-post-bool-v6.patch

File spirit-transform-attribute-post-bool-v6.patch, 37.2 KB (added by oakad@…, 10 years ago)

Fix an unfortunately missed "bit rot" in v5 arising from changed function attribute names.

  • boost/spirit/home/qi/action/action.hpp

     
    7070                {
    7171                    // Do up-stream transformation, this integrates the results
    7272                    // back into the original attribute value, if appropriate.
    73                     traits::post_transform(attr_, attr);
    74                     return true;
     73                    if (traits::post_transform(attr_, attr))
     74                        return true;
    7575                }
    7676
    7777                // reset iterators if semantic action failed the match
  • boost/spirit/home/qi/nonterminal/rule.hpp

     
    277277        {
    278278            if (f)
    279279            {
     280                Iterator iter = first;
    280281                // do a preskip if this is an implied lexeme
    281282                if (is_same<skipper_type, unused_type>::value)
    282                     qi::skip_over(first, last, skipper);
     283                    qi::skip_over(iter, last, skipper);
    283284
    284285                typedef traits::make_attribute<attr_type, Attribute> make_attribute;
    285286
     
    301302                // fourth parameter can't be converted to a required target type
    302303                // then you are probably trying to use a rule or a grammar with
    303304                // an incompatible skipper type.
    304                 if (f(first, last, context, skipper))
     305                if (f(iter, last, context, skipper))
    305306                {
    306307                    // do up-stream transformation, this integrates the results
    307308                    // back into the original attribute value, if appropriate
    308                     traits::post_transform(attr_param, attr_);
    309                     return true;
     309                    if (traits::post_transform(attr_param, attr_)) {
     310                        first = iter;
     311                        return true;
     312                    }
    310313                }
    311314
    312315                // inform attribute transformation of failed rhs
     
    323326        {
    324327            if (f)
    325328            {
     329                Iterator iter = first;
    326330                // do a preskip if this is an implied lexeme
    327331                if (is_same<skipper_type, unused_type>::value)
    328                     qi::skip_over(first, last, skipper);
     332                    qi::skip_over(iter, last, skipper);
    329333
    330334                typedef traits::make_attribute<attr_type, Attribute> make_attribute;
    331335
     
    347351                // fourth parameter can't be converted to a required target type
    348352                // then you are probably trying to use a rule or a grammar with
    349353                // an incompatible skipper type.
    350                 if (f(first, last, context, skipper))
     354                if (f(iter, last, context, skipper))
    351355                {
    352356                    // do up-stream transformation, this integrates the results
    353357                    // back into the original attribute value, if appropriate
    354                     traits::post_transform(attr_param, attr_);
    355                     return true;
     358                    if (traits::post_transform(attr_param, attr_)) {
     359                        first = iter;
     360                        return true;
     361                    }
    356362                }
    357363
    358364                // inform attribute transformation of failed rhs
  • boost/spirit/home/qi/detail/attributes.hpp

     
    2222
    2323        static Transformed pre(Exposed&) { return Transformed(); }
    2424
    25         static void post(Exposed& val, Transformed const& attr)
     25        static bool post(Exposed& val, Transformed const& attr)
    2626        {
    2727            traits::assign_to(attr, val);
     28            return true;
    2829        }
    2930
    3031        // fail() will be called by Qi rule's if the rhs failed parsing
     
    3738    {
    3839        typedef Attribute& type;
    3940        static Attribute& pre(Attribute& val) { return val; }
    40         static void post(Attribute&, Attribute const&) {}
     41        static bool post(Attribute&, Attribute const&) { return true; }
    4142        static void fail(Attribute&) {}
    4243    };
    4344
     
    4748        typedef Transformed type;
    4849
    4950        static Transformed pre(Exposed& val) { return Transformed(val); }
    50         static void post(Exposed&, Transformed const&) { /* no-op */ }
     51        static bool post(Exposed&, Transformed const&) { return true; }
    5152
    5253        // fail() will be called by Qi rule's if the rhs failed parsing
    5354        static void fail(Exposed&) {}
     
    5960    {
    6061        typedef Attribute& type;
    6162        static Attribute& pre(Attribute& val) { return val; }
    62         static void post(Attribute&, Attribute const&) {}
     63        static bool post(Attribute&, Attribute const&) { return true; }
    6364        static void fail(Attribute&) {}
    6465    };
    6566
     
    8788                val = Transformed();
    8889            return boost::get<Transformed>(val);
    8990        }
    90         static void post(boost::optional<Exposed>&, Transformed const&) {}
     91        static bool post(boost::optional<Exposed>&, Transformed const&) { return true; }
    9192        static void fail(boost::optional<Exposed>& val)
    9293        {
    9394             val = none_t();    // leave optional uninitialized if rhs failed
     
    100101    {
    101102        typedef Attribute& type;
    102103        static Attribute& pre(Attribute& val) { return val; }
    103         static void post(Attribute&, Attribute const&) {}
     104        static bool post(Attribute&, Attribute const&) { return true; }
    104105        static void fail(Attribute&) {}
    105106    };
    106107
     
    110111    {
    111112        typedef unused_type type;
    112113        static unused_type pre(unused_type) { return unused; }
    113         static void post(unused_type, unused_type) {}
     114        static bool post(unused_type, unused_type) { return true; }
    114115        static void fail(unused_type) {}
    115116    };
    116117
     
    160161
    161162    ///////////////////////////////////////////////////////////////////////////
    162163    template <typename Exposed, typename Transformed>
    163     void post_transform(Exposed& dest, Transformed const& attr)
     164    bool post_transform(Exposed& dest, Transformed const& attr)
    164165    {
    165166        return transform_attribute<Exposed, Transformed, qi::domain>::post(dest, attr);
    166167    }
  • boost/spirit/home/qi/auxiliary/attr_cast.hpp

     
    9191            transform;
    9292
    9393            typename transform::type attr_ = transform::pre(attr_param);
     94            Iterator iter = first;
    9495
    95             if (!compile<qi::domain>(subject).
    96                     parse(first, last, context, skipper, attr_))
     96            if (compile<qi::domain>(subject)
     97                .parse(iter, last, context, skipper, attr_))
    9798            {
    98                 transform::fail(attr_param);
    99                 return false;
     99                // do up-stream transformation, this mainly integrates the resu
     100                // back into the original attribute value, if appropriate
     101                if (traits::post_transform(attr_param, attr_)) {
     102                    first = iter;
     103                    return true;
     104                }
    100105            }
    101106
    102             // do up-stream transformation, this mainly integrates the results
    103             // back into the original attribute value, if appropriate
    104             traits::post_transform(attr_param, attr_);
    105             return true;
     107             transform::fail(attr_param);
     108             return false;
    106109        }
    107110
    108111        template <typename Context>
  • boost/spirit/home/support/adapt_adt_attributes.hpp

     
    257257        {
    258258            return val;
    259259        }
    260         static void
     260        static bool
    261261        post(
    262262            fusion::extension::adt_attribute_proxy<T, N, false>& val
    263263          , Attribute const& attr)
    264264        {
    265265            val = attr;
     266            return true;
    266267        }
    267268        static void
    268269        fail(fusion::extension::adt_attribute_proxy<T, N, false>&)
     
    289290        {
    290291            return val;
    291292        }
    292         static void
     293        static bool
    293294        post(
    294295            fusion::extension::adt_attribute_proxy<T, N, Const>&
    295296          , Attribute const&)
    296297        {
     298            return true;
    297299        }
    298300        static void
    299301        fail(fusion::extension::adt_attribute_proxy<T, N, Const>&)
  • boost/spirit/repository/home/qi/nonterminal/subrule.hpp

     
    213213            // without passing values for them.
    214214            context_type context(*this, attr_);
    215215
    216             if (def.binder(first, last, context, skipper))
     216            Iterator i = first;
     217
     218            if (def.binder(i, last, context, skipper))
    217219            {
    218220                // do up-stream transformation, this integrates the results
    219221                // back into the original attribute value, if appropriate
    220                 traits::post_transform(attr, attr_);
    221                 return true;
     222                if (traits::post_transform(attr, attr_)) {
     223                    first = i;
     224                    return true;
     225                }
    222226            }
    223227
    224228            // inform attribute transformation of failed rhs
     
    267271            // passing values of incompatible types for them.
    268272            context_type context(*this, attr_, params, caller_context);
    269273
    270             if (def.binder(first, last, context, skipper))
     274            Iterator i = first;
     275
     276            if (def.binder(i, last, context, skipper))
    271277            {
    272278                // do up-stream transformation, this integrates the results
    273279                // back into the original attribute value, if appropriate
    274                 traits::post_transform(attr, attr_);
    275                 return true;
     280                if (traits::post_transform(attr, attr_)) {
     281                    first = i;
     282                    return true;
     283                }
    276284            }
    277285
    278286            // inform attribute transformation of failed rhs
  • libs/spirit/example/support/utree/sexpr_parser.hpp

     
    2121  typedef unused_type type;
    2222
    2323  static unused_type pre (utree::nil_type&) { return unused_type(); }
    24   static void post (utree::nil_type&, unused_type) { }
     24  static bool post (utree::nil_type&, unused_type) { return true; }
    2525  static void fail (utree::nil_type&) { }
    2626};
    2727
  • libs/spirit/example/qi/attr_cast.cpp

     
     1//  Copyright (c) 2011 Alex Dubov
     2//
     3//  Distributed under the Boost Software License, Version 1.0. (See accompanying
     4//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
     5
     6//  This example demonstrates a method to conditionally propagate
     7//  a parsed value to a value restricted attribute type.
     8
     9#include <boost/spirit/include/qi.hpp>
     10#include <boost/spirit/include/phoenix_operator.hpp>
     11
     12namespace qi = boost::spirit::qi;
     13namespace fusion = boost::fusion;
     14
     15template <typename P, typename T>
     16void test_parser_attr(
     17    char const* input, P const& p, T& attr, bool full_match = true)
     18{
     19    using boost::spirit::qi::parse;
     20
     21    char const* f(input);
     22    char const* l(f + strlen(f));
     23    if (parse(f, l, p, attr) && (!full_match || (f == l)))
     24        std::cout << "ok" << std::endl;
     25    else
     26        std::cout << "fail" << std::endl;
     27}
     28
     29//[reference_qi_auxiliary_attr_cast_data2
     30// Test structure we want to use in place of an int. Lets pretend we only
     31// want it to hold values strictly less that 100.
     32struct less_than_100
     33{
     34    int i;
     35};
     36
     37// Counter variable we shall use later on.
     38int greater_than_100_cnt = 0;
     39
     40// Custom attribute transformations for our primitive range restricted type.
     41namespace boost { namespace spirit { namespace traits
     42{
     43    template <>
     44    struct transform_attribute<less_than_100, int, qi::domain>
     45    {
     46        typedef int type;
     47
     48        // Any value less than 100 is still a valid int, so no problem here.
     49        static type pre(less_than_100& val) { return val.i; }
     50
     51        // Not every int is less than 100, so we better do some checking.
     52        static bool post(less_than_100& val, type const& attr)
     53        {
     54            if (attr < 100)
     55            {
     56                val.i = attr;
     57                return true;
     58            }
     59            else
     60            {
     61                return false;
     62            }
     63        }
     64        static void fail(less_than_100&) {}
     65    };
     66}}}
     67//]
     68
     69namespace std
     70{
     71    ostream& operator<<(ostream &os, less_than_100 val)
     72    {
     73        return (os << val.i);
     74    }
     75
     76    ostream& operator<<(ostream &os, std::vector<less_than_100> const& val)
     77    {
     78        for (size_t cnt = 0; cnt < val.size(); ++cnt)
     79            os << val[cnt] << ", ";
     80        return os;
     81    }
     82
     83}
     84
     85
     86///////////////////////////////////////////////////////////////////////////////
     87int main()
     88{
     89    //[reference_qi_attr_cast2
     90    using qi::int_;
     91    using qi::attr_cast;
     92    using qi::omit;
     93    using boost::phoenix::ref;
     94
     95    less_than_100 d = { 0 };
     96
     97    // Just like the previous example, the parser succedes.
     98    test_parser_attr("1", attr_cast(int_), d);
     99    std::cout << d << std::endl;
     100
     101    // Yet, if we try a value, larger than 100 (as defined above), the parser
     102    // fails.
     103    test_parser_attr("101", attr_cast(int_), d);
     104    std::cout << d << std::endl;
     105
     106    // To demonstrate the facility even further, lets pretend we want to parse
     107    // a list of numbers, storing good values into a container and counting
     108    // the bad ones. We will try to convert the numbers from the comma
     109    // separated list into less_than_100 values, and if a number or two happen
     110    // to be out of range we will drop them using the qi::omit directive and
     111    // increment our greater_than_100_cnt variable.
     112    std::vector<less_than_100> v1;
     113
     114    test_parser_attr("10,20,105,39,114,3,121",
     115                     (attr_cast<less_than_100>(int_)
     116                      | omit[int_][ref(greater_than_100_cnt)++]) % ',',
     117                     v1);
     118    // The below print outs should correctly report the 3 out of range values,
     119    // as well as 4 correctly assigned ones. The container will still hold
     120    // 7 values, with "bad" unassigned values substituted by defaul constructed
     121    // ones (the specific value to substitute can be defined in
     122    // transform_attribute::fail() method).
     123    std::cout << "Values out of range: " << greater_than_100_cnt << std::endl;
     124    std::cout << "Good values: " << v1 << std::endl;
     125    //]
     126    return 0;
     127}
     128//  Copyright (c) 2011 Alex Dubov
     129//
     130//  Distributed under the Boost Software License, Version 1.0. (See accompanying
     131//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
     132
     133//  This example demonstrates a method to conditionally propagate
     134//  a parsed value to a value restricted attribute type.
     135
     136#include <boost/spirit/include/qi.hpp>
     137#include <boost/spirit/include/phoenix_operator.hpp>
     138
     139namespace qi = boost::spirit::qi;
     140namespace fusion = boost::fusion;
     141
     142template <typename P, typename T>
     143void test_parser_attr(
     144    char const* input, P const& p, T& attr, bool full_match = true)
     145{
     146    using boost::spirit::qi::parse;
     147
     148    char const* f(input);
     149    char const* l(f + strlen(f));
     150    if (parse(f, l, p, attr) && (!full_match || (f == l)))
     151        std::cout << "ok" << std::endl;
     152    else
     153        std::cout << "fail" << std::endl;
     154}
     155
     156//[reference_qi_auxiliary_attr_cast_data2
     157// Test structure we want to use in place of an int. Lets pretend we only
     158// want it to hold values strictly less that 100.
     159struct less_than_100
     160{
     161    int i;
     162};
     163
     164// Counter variable we shall use later on.
     165int greater_than_100_cnt = 0;
     166
     167// Custom attribute transformations for our primitive range restricted type.
     168namespace boost { namespace spirit { namespace traits
     169{
     170    template <>
     171    struct transform_attribute<less_than_100, int, qi::domain>
     172    {
     173        typedef int type;
     174
     175        // Any value less than 100 is still a valid int, so no problem here.
     176        static type pre(less_than_100& val) { return val.i; }
     177
     178        // Not every int is less than 100, so we better do some checking.
     179        static bool post(less_than_100& val, type const& attr)
     180        {
     181            if (attr < 100)
     182            {
     183                val.i = attr;
     184                return true;
     185            }
     186            else
     187            {
     188                return false;
     189            }
     190        }
     191        static void fail(less_than_100&) {}
     192    };
     193}}}
     194//]
     195
     196namespace std
     197{
     198    ostream& operator<<(ostream &os, less_than_100 val)
     199    {
     200        return (os << val.i);
     201    }
     202
     203    ostream& operator<<(ostream &os, std::vector<less_than_100> const& val)
     204    {
     205        for (size_t cnt = 0; cnt < val.size(); ++cnt)
     206            os << val[cnt] << ", ";
     207        return os;
     208    }
     209
     210}
     211
     212
     213///////////////////////////////////////////////////////////////////////////////
     214int main()
     215{
     216    //[reference_qi_attr_cast2
     217    using qi::int_;
     218    using qi::attr_cast;
     219    using qi::omit;
     220    using boost::phoenix::ref;
     221
     222    less_than_100 d = { 0 };
     223
     224    // Just like the previous example, the parser succedes.
     225    test_parser_attr("1", attr_cast(int_), d);
     226    std::cout << d << std::endl;
     227
     228    // Yet, if we try a value, larger than 100 (as defined above), the parser
     229    // fails.
     230    test_parser_attr("101", attr_cast(int_), d);
     231    std::cout << d << std::endl;
     232
     233    // To demonstrate the facility even further, lets pretend we want to parse
     234    // a list of numbers, storing good values into a container and counting
     235    // the bad ones. We will try to convert the numbers from the comma
     236    // separated list into less_than_100 values, and if a number or two happen
     237    // to be out of range we will drop them using the qi::omit directive and
     238    // increment our greater_than_100_cnt variable.
     239    std::vector<less_than_100> v1;
     240
     241    test_parser_attr("10,20,105,39,114,3,121",
     242                     (attr_cast<less_than_100>(int_)
     243                      | omit[int_][ref(greater_than_100_cnt)++]) % ',',
     244                     v1);
     245    // The below print outs should correctly report the 3 out of range values,
     246    // as well as 4 correctly assigned ones. The container will still hold
     247    // 7 values, with "bad" unassigned values substituted by defaul constructed
     248    // ones (the specific value to substitute can be defined in
     249    // transform_attribute::fail() method).
     250    std::cout << "Values out of range: " << greater_than_100_cnt << std::endl;
     251    std::cout << "Good values: " << v1 << std::endl;
     252    //]
     253    return 0;
     254}
     255//  Copyright (c) 2011 Alex Dubov
     256//
     257//  Distributed under the Boost Software License, Version 1.0. (See accompanying
     258//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
     259
     260//  This example demonstrates a method to conditionally propagate
     261//  a parsed value to a value restricted attribute type.
     262
     263#include <boost/spirit/include/qi.hpp>
     264#include <boost/spirit/include/phoenix_operator.hpp>
     265
     266namespace qi = boost::spirit::qi;
     267namespace fusion = boost::fusion;
     268
     269template <typename P, typename T>
     270void test_parser_attr(
     271    char const* input, P const& p, T& attr, bool full_match = true)
     272{
     273    using boost::spirit::qi::parse;
     274
     275    char const* f(input);
     276    char const* l(f + strlen(f));
     277    if (parse(f, l, p, attr) && (!full_match || (f == l)))
     278        std::cout << "ok" << std::endl;
     279    else
     280        std::cout << "fail" << std::endl;
     281}
     282
     283//[reference_qi_auxiliary_attr_cast_data2
     284// Test structure we want to use in place of an int. Lets pretend we only
     285// want it to hold values strictly less that 100.
     286struct less_than_100
     287{
     288    int i;
     289};
     290
     291// Counter variable we shall use later on.
     292int greater_than_100_cnt = 0;
     293
     294// Custom attribute transformations for our primitive range restricted type.
     295namespace boost { namespace spirit { namespace traits
     296{
     297    template <>
     298    struct transform_attribute<less_than_100, int, qi::domain>
     299    {
     300        typedef int type;
     301
     302        // Any value less than 100 is still a valid int, so no problem here.
     303        static type pre(less_than_100& val) { return val.i; }
     304
     305        // Not every int is less than 100, so we better do some checking.
     306        static bool post(less_than_100& val, type const& attr)
     307        {
     308            if (attr < 100)
     309            {
     310                val.i = attr;
     311                return true;
     312            }
     313            else
     314            {
     315                return false;
     316            }
     317        }
     318        static void fail(less_than_100&) {}
     319    };
     320}}}
     321//]
     322
     323namespace std
     324{
     325    ostream& operator<<(ostream &os, less_than_100 val)
     326    {
     327        return (os << val.i);
     328    }
     329
     330    ostream& operator<<(ostream &os, std::vector<less_than_100> const& val)
     331    {
     332        for (size_t cnt = 0; cnt < val.size(); ++cnt)
     333            os << val[cnt] << ", ";
     334        return os;
     335    }
     336
     337}
     338
     339
     340///////////////////////////////////////////////////////////////////////////////
     341int main()
     342{
     343    //[reference_qi_attr_cast2
     344    using qi::int_;
     345    using qi::attr_cast;
     346    using qi::omit;
     347    using boost::phoenix::ref;
     348
     349    less_than_100 d = { 0 };
     350
     351    // Just like the previous example, the parser succedes.
     352    test_parser_attr("1", attr_cast(int_), d);
     353    std::cout << d << std::endl;
     354
     355    // Yet, if we try a value, larger than 100 (as defined above), the parser
     356    // fails.
     357    test_parser_attr("101", attr_cast(int_), d);
     358    std::cout << d << std::endl;
     359
     360    // To demonstrate the facility even further, lets pretend we want to parse
     361    // a list of numbers, storing good values into a container and counting
     362    // the bad ones. We will try to convert the numbers from the comma
     363    // separated list into less_than_100 values, and if a number or two happen
     364    // to be out of range we will drop them using the qi::omit directive and
     365    // increment our greater_than_100_cnt variable.
     366    std::vector<less_than_100> v1;
     367
     368    test_parser_attr("10,20,105,39,114,3,121",
     369                     (attr_cast<less_than_100>(int_)
     370                      | omit[int_][ref(greater_than_100_cnt)++]) % ',',
     371                     v1);
     372    // The below print outs should correctly report the 3 out of range values,
     373    // as well as 4 correctly assigned ones. The container will still hold
     374    // 7 values, with "bad" unassigned values substituted by defaul constructed
     375    // ones (the specific value to substitute can be defined in
     376    // transform_attribute::fail() method).
     377    std::cout << "Values out of range: " << greater_than_100_cnt << std::endl;
     378    std::cout << "Good values: " << v1 << std::endl;
     379    //]
     380    return 0;
     381}
     382//  Copyright (c) 2011 Alex Dubov
     383//
     384//  Distributed under the Boost Software License, Version 1.0. (See accompanying
     385//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
     386
     387//  This example demonstrates a method to conditionally propagate
     388//  a parsed value to a value restricted attribute type.
     389
     390#include <boost/spirit/include/qi.hpp>
     391#include <boost/spirit/include/phoenix_operator.hpp>
     392
     393namespace qi = boost::spirit::qi;
     394namespace fusion = boost::fusion;
     395
     396template <typename P, typename T>
     397void test_parser_attr(
     398    char const* input, P const& p, T& attr, bool full_match = true)
     399{
     400    using boost::spirit::qi::parse;
     401
     402    char const* f(input);
     403    char const* l(f + strlen(f));
     404    if (parse(f, l, p, attr) && (!full_match || (f == l)))
     405        std::cout << "ok" << std::endl;
     406    else
     407        std::cout << "fail" << std::endl;
     408}
     409
     410//[reference_qi_auxiliary_attr_cast_data2
     411// Test structure we want to use in place of an int. Lets pretend we only
     412// want it to hold values strictly less that 100.
     413struct less_than_100
     414{
     415    int i;
     416};
     417
     418// Counter variable we shall use later on.
     419int greater_than_100_cnt = 0;
     420
     421// Custom attribute transformations for our primitive range restricted type.
     422namespace boost { namespace spirit { namespace traits
     423{
     424    template <>
     425    struct transform_attribute<less_than_100, int, qi::domain>
     426    {
     427        typedef int type;
     428
     429        // Any value less than 100 is still a valid int, so no problem here.
     430        static type pre(less_than_100& val) { return val.i; }
     431
     432        // Not every int is less than 100, so we better do some checking.
     433        static bool post(less_than_100& val, type const& attr)
     434        {
     435            if (attr < 100)
     436            {
     437                val.i = attr;
     438                return true;
     439            }
     440            else
     441            {
     442                return false;
     443            }
     444        }
     445        static void fail(less_than_100&) {}
     446    };
     447}}}
     448//]
     449
     450namespace std
     451{
     452    ostream& operator<<(ostream &os, less_than_100 val)
     453    {
     454        return (os << val.i);
     455    }
     456
     457    ostream& operator<<(ostream &os, std::vector<less_than_100> const& val)
     458    {
     459        for (size_t cnt = 0; cnt < val.size(); ++cnt)
     460            os << val[cnt] << ", ";
     461        return os;
     462    }
     463
     464}
     465
     466
     467///////////////////////////////////////////////////////////////////////////////
     468int main()
     469{
     470    //[reference_qi_attr_cast2
     471    using qi::int_;
     472    using qi::attr_cast;
     473    using qi::omit;
     474    using boost::phoenix::ref;
     475
     476    less_than_100 d = { 0 };
     477
     478    // Just like the previous example, the parser succedes.
     479    test_parser_attr("1", attr_cast(int_), d);
     480    std::cout << d << std::endl;
     481
     482    // Yet, if we try a value, larger than 100 (as defined above), the parser
     483    // fails.
     484    test_parser_attr("101", attr_cast(int_), d);
     485    std::cout << d << std::endl;
     486
     487    // To demonstrate the facility even further, lets pretend we want to parse
     488    // a list of numbers, storing good values into a container and counting
     489    // the bad ones. We will try to convert the numbers from the comma
     490    // separated list into less_than_100 values, and if a number or two happen
     491    // to be out of range we will drop them using the qi::omit directive and
     492    // increment our greater_than_100_cnt variable.
     493    std::vector<less_than_100> v1;
     494
     495    test_parser_attr("10,20,105,39,114,3,121",
     496                     (attr_cast<less_than_100>(int_)
     497                      | omit[int_][ref(greater_than_100_cnt)++]) % ',',
     498                     v1);
     499    // The below print outs should correctly report the 3 out of range values,
     500    // as well as 4 correctly assigned ones. The container will still hold
     501    // 7 values, with "bad" unassigned values substituted by defaul constructed
     502    // ones (the specific value to substitute can be defined in
     503    // transform_attribute::fail() method).
     504    std::cout << "Values out of range: " << greater_than_100_cnt << std::endl;
     505    std::cout << "Good values: " << v1 << std::endl;
     506    //]
     507    return 0;
     508}
  • libs/spirit/example/qi/adapt_template_struct.cpp

     
    4444        typedef fusion::vector<A&, B&> type;
    4545
    4646        static type pre(client::data<A, B>& val) { return type(val.a, val.b); }
    47         static void post(client::data<A, B>&, fusion::vector<A&, B&> const&) {}
     47        static bool post(client::data<A, B>&, fusion::vector<A&, B&> const&) { return true; }
    4848        static void fail(client::data<A, B>&) {}
    4949    };
    5050}}}
  • libs/spirit/example/qi/parse_date.cpp

     
    5454        // We need to initialize the attribute supplied to the rule (referenced
    5555        // by the first argument) with the values taken from the parsing
    5656        // results (referenced by the second argument).
    57         static void post(boost::gregorian::date& d, date_parts const& v)
     57        static bool post(boost::gregorian::date& d, date_parts const& v)
    5858        {
    5959            d = boost::gregorian::date(fusion::at_c<0>(v), fusion::at_c<1>(v)
    6060              , fusion::at_c<2>(v));
     61            return true;
    6162        }
    6263
    6364        // The function fail() is called whenever the parsing of the right hand
  • libs/spirit/example/qi/Jamfile

     
    3636exe boost_array : boost_array.cpp ;
    3737exe display_attribute_type : display_attribute_type.cpp ;
    3838exe adapt_template_struct : adapt_template_struct.cpp ;
     39exe attr_cast : attr_cast.cpp ;
    3940
    4041exe unescaped_string : unescaped_string.cpp ;
    4142
  • libs/spirit/example/qi/reference.cpp

     
    292292    {
    293293        typedef int& type;
    294294        static int& pre(int_data& d) { return d.i; }
    295         static void post(int_data& val, int const& attr) {}
     295        // this particular transformation is always successful
     296        static bool post(int_data& val, int const& attr) { return true; }
    296297        static void fail(int_data&) {}
    297298    };
    298299}}}
  • libs/spirit/test/qi/regression_transform_assignment.cpp

     
    3131            return fusion::tie(parts.second, parts.first);
    3232        }
    3333
    34         static void post(foo_parts &, type const &) {}
     34        static bool post(foo_parts &, type const &) { return true; }
    3535        static void fail(foo_parts &) {}
    3636    };
    3737}}}   
  • libs/spirit/test/qi/attribute1.cpp

     
    2020#include <boost/spirit/include/qi_operator.hpp>
    2121#include <boost/spirit/include/qi_nonterminal.hpp>
    2222#include <boost/spirit/include/qi_auxiliary.hpp>
     23#include <boost/spirit/include/qi_directive.hpp>
    2324
    2425#include <iostream>
    2526#include <vector>
     
    6061    {
    6162        typedef int type;
    6263        static int pre(test_int_data1& d) { return d.i; }
    63         static void post(test_int_data1& d, int i) { d.i = i; }
     64        static bool post(test_int_data1& d, int i) { d.i = i; return true; }
    6465        static void fail(test_int_data1&) {}
    6566    };
    6667}}}
     
    8081    {
    8182        typedef int& type;
    8283        static int& pre(test_int_data2& d) { return d.i; }
    83         static void post(test_int_data2&, int const&) {}
     84        static bool post(test_int_data2&, int const&) { return true; }
    8485        static void fail(test_int_data2&) {}
    8586    };
    8687}}}
    8788
    8889///////////////////////////////////////////////////////////////////////////////
     90struct test_int_data3
     91{
     92    int i;
     93};
     94
     95// we provide a custom attribute transformation taking copy of the actual
     96// attribute value, simulating more complex type transformations which
     97// may fail due to target type limitations (in this case, restricted range).
     98namespace boost { namespace spirit { namespace traits
     99{
     100    template <>
     101    struct transform_attribute<test_int_data3, int, qi::domain>
     102    {
     103        typedef int type;
     104        static int pre(test_int_data3& d) { return d.i; }
     105        static bool post(test_int_data3& d, int i)
     106        {
     107            if (i < 5)
     108            {
     109                d.i = i;
     110                return true;
     111            }
     112            else
     113            {
     114                return false;
     115            }
     116        }
     117        static void fail(test_int_data3& d)
     118        {
     119           d.i = -1;
     120        }
     121    };
     122}}}
     123
     124///////////////////////////////////////////////////////////////////////////////
    89125int
    90126main()
    91127{
     
    173209        BOOST_TEST(v.size() == 2 && v[0].i == 1 && v[1].i == 2);
    174210    }
    175211
     212    // testing controlled failure of attribute transformation
     213    {
     214        std::vector<test_int_data3> v;
     215        // the parser is expected to fail at the second value
     216        BOOST_TEST(!test_attr("3,7,2"
     217          , qi::attr_cast<test_int_data3>(qi::int_) % ',', v));
     218        BOOST_TEST(v.size() == 1 && v[0].i == 3);
     219
     220        // the parser is expected to hit an alternative and proceed
     221        v.clear();
     222        BOOST_TEST(test_attr("3,7,2"
     223          , (qi::attr_cast<test_int_data3>(qi::int_) | qi::omit[qi::int_]) % ',', v));
     224        BOOST_TEST(v.size() == 3 && v[0].i == 3 && v[1].i == -1 && v[2].i == 2);
     225    }
    176226    return boost::report_errors();
    177227}
  • libs/spirit/test/qi/attribute2.cpp

     
    6060    {
    6161        typedef int type;
    6262        static int pre(test_int_data1& d) { return d.i; }
    63         static void post(test_int_data1& d, int i) { d.i = i; }
     63        static bool post(test_int_data1& d, int i) { d.i = i; return true; }
    6464        static void fail(test_int_data1&) {}
    6565    };
    6666}}}
     
    8080    {
    8181        typedef int& type;
    8282        static int& pre(test_int_data2& d) { return d.i; }
    83         static void post(test_int_data2&, int const&) {}
     83        static bool post(test_int_data2&, int const&) { return true; }
    8484        static void fail(test_int_data2&) {}
    8585    };
    8686}}}
  • libs/spirit/doc/advanced/customization_points.qbk

     
    477477        typedef <unspecified> type;
    478478
    479479        static type pre(Exposed& val);
    480         static void post(Exposed& val, type attr);    // Qi only
     480        static bool post(Exposed& val, type attr);    // Qi only
    481481        static void fail(Exposed&);                   // Qi only
    482482    };
    483483
     
    533533                         as exposed by the metafunction `type`). This function
    534534                         will be called in /Qi/ and for /Karma/.]]
    535535    [[
    536 ``void transform_attribute<Exposed, Transformed, Domain>::post(exposed, transformed)``]
     536``bool transform_attribute<Exposed, Transformed, Domain>::post(exposed, transformed)``]
    537537                        [Do `post`-transformation after the invocation of the
    538538                         right hand side component for `rule` (or the embedded
    539539                         component for `attr_cast`). This takes the original
    540540                         attribute as supplied by the user and the attribute
    541541                         as returned from the right hand side (embedded)
    542542                         component and is expected to propagate the result back
    543                          into the supplied attribute instance. This function
    544                          will be called in /Qi/ only.]]
     543                         into the supplied attribute instance. Can return `false`
     544                         if propagation can not be successfully performed, thus
     545                         failing the parser which invoked the transormation. This
     546                         function will be called in /Qi/ only.]]
    545547    [[
    546548``void transform_attribute<Exposed, Transformed, Domain>::fail(exposed)``]
    547549                        [Handling failing parse operations of the
  • libs/spirit/doc/qi/auxiliary.qbk

     
    217217
    218218[reference_qi_attr_cast1]
    219219
     220[heading Advanced Example]
     221
     222Just like semantic actions, __customize_transform_attribute__ has the ability
     223to signal failure back to the parser. This may happen if there's no obvious
     224way to convert the parsed attribute value back to the exposed attribute type.
     225Common examples of such behavior are enumerations and range restricted
     226arithmetic types, but, of course, other similar use cases are also possible.
     227
     228Lets expand the definitions above into a slightly more complex example:
     229
     230[import ../../example/qi/attr_cast.cpp]
     231[reference_qi_auxiliary_attr_cast_data2]
     232
     233Now we can attempt to parse some values which may not necessarily fit into
     234a range limited type we defined:
     235
     236[reference_qi_attr_cast2]
     237
     238The full cpp file for this example can be found here: [@../../example/qi/attr_cast.cpp]
     239
    220240[endsect]
    221241
    222242