Ticket #6050: spirit-transform-attribute-post-bool-v3.patch
File spirit-transform-attribute-post-bool-v3.patch, 24.3 KB (added by , 11 years ago) |
---|
-
boost/spirit/repository/home/qi/nonterminal/subrule.hpp
213 213 // without passing values for them. 214 214 context_type context(*this, attr_); 215 215 216 if (def.binder(first, last, context, skipper)) 216 Iterator i = first; 217 218 if (def.binder(i, last, context, skipper)) 217 219 { 218 220 // do up-stream transformation, this integrates the results 219 221 // 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 } 222 226 } 223 227 224 228 // inform attribute transformation of failed rhs … … 267 271 // passing values of incompatible types for them. 268 272 context_type context(*this, attr_, params, caller_context); 269 273 270 if (def.binder(first, last, context, skipper)) 274 Iterator i = first; 275 276 if (def.binder(i, last, context, skipper)) 271 277 { 272 278 // do up-stream transformation, this integrates the results 273 279 // 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 } 276 284 } 277 285 278 286 // inform attribute transformation of failed rhs -
boost/spirit/home/qi/nonterminal/rule.hpp
296 296 // attributes, without passing values for them. 297 297 context_type context(attr_); 298 298 299 Iterator i = first; 300 299 301 // If you are seeing a compilation error here stating that the 300 302 // fourth parameter can't be converted to a required target type 301 303 // then you are probably trying to use a rule or a grammar with 302 304 // an incompatible skipper type. 303 if (f( first, last, context, skipper))305 if (f(i, last, context, skipper)) 304 306 { 305 307 // do up-stream transformation, this integrates the results 306 308 // back into the original attribute value, if appropriate 307 traits::post_transform(attr, attr_); 308 return true; 309 if (traits::post_transform(attr, attr_)) { 310 first = i; 311 return true; 312 } 309 313 } 310 314 311 315 // inform attribute transformation of failed rhs … … 342 346 // attributes, passing values of incompatible types for them. 343 347 context_type context(attr_, params, caller_context); 344 348 349 Iterator i = first; 350 345 351 // If you are seeing a compilation error here stating that the 346 352 // fourth parameter can't be converted to a required target type 347 353 // then you are probably trying to use a rule or a grammar with 348 354 // an incompatible skipper type. 349 if (f( first, last, context, skipper))355 if (f(i, last, context, skipper)) 350 356 { 351 357 // do up-stream transformation, this integrates the results 352 358 // back into the original attribute value, if appropriate 353 traits::post_transform(attr, attr_); 354 return true; 359 if (traits::post_transform(attr, attr_)) { 360 first = i; 361 return true; 362 } 355 363 } 356 364 357 365 // inform attribute transformation of failed rhs -
boost/spirit/home/qi/detail/attributes.hpp
22 22 23 23 static Transformed pre(Exposed&) { return Transformed(); } 24 24 25 static voidpost(Exposed& val, Transformed const& attr)25 static bool post(Exposed& val, Transformed const& attr) 26 26 { 27 27 traits::assign_to(attr, val); 28 return true; 28 29 } 29 30 30 31 // fail() will be called by Qi rule's if the rhs failed parsing … … 37 38 { 38 39 typedef Attribute& type; 39 40 static Attribute& pre(Attribute& val) { return val; } 40 static void post(Attribute&, Attribute const&) {}41 static bool post(Attribute&, Attribute const&) { return true; } 41 42 static void fail(Attribute&) {} 42 43 }; 43 44 … … 47 48 typedef Transformed type; 48 49 49 50 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; } 51 52 52 53 // fail() will be called by Qi rule's if the rhs failed parsing 53 54 static void fail(Exposed&) {} … … 59 60 { 60 61 typedef Attribute& type; 61 62 static Attribute& pre(Attribute& val) { return val; } 62 static void post(Attribute&, Attribute const&) {}63 static bool post(Attribute&, Attribute const&) { return true; } 63 64 static void fail(Attribute&) {} 64 65 }; 65 66 … … 87 88 val = Transformed(); 88 89 return boost::get<Transformed>(val); 89 90 } 90 static void post(boost::optional<Exposed>&, Transformed const&) {}91 static bool post(boost::optional<Exposed>&, Transformed const&) { return true; } 91 92 static void fail(boost::optional<Exposed>& val) 92 93 { 93 94 val = none_t(); // leave optional uninitialized if rhs failed … … 100 101 { 101 102 typedef Attribute& type; 102 103 static Attribute& pre(Attribute& val) { return val; } 103 static void post(Attribute&, Attribute const&) {}104 static bool post(Attribute&, Attribute const&) { return true; } 104 105 static void fail(Attribute&) {} 105 106 }; 106 107 … … 110 111 { 111 112 typedef unused_type type; 112 113 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; } 114 115 static void fail(unused_type) {} 115 116 }; 116 117 … … 160 161 161 162 /////////////////////////////////////////////////////////////////////////// 162 163 template <typename Exposed, typename Transformed> 163 voidpost_transform(Exposed& dest, Transformed const& attr)164 bool post_transform(Exposed& dest, Transformed const& attr) 164 165 { 165 166 return transform_attribute<Exposed, Transformed, qi::domain>::post(dest, attr); 166 167 } -
boost/spirit/home/qi/auxiliary/attr_cast.hpp
92 92 93 93 typename transform::type attr_ = transform::pre(attr); 94 94 95 if (!compile<qi::domain>(subject). 96 parse(first, last, context, skipper, attr_)) 95 Iterator i = first; 96 97 if (compile<qi::domain>(subject). 98 parse(i, last, context, skipper, attr_)) 97 99 { 98 transform::fail(attr); 99 return false; 100 // do up-stream transformation, this mainly integrates the results 101 // back into the original attribute value, if appropriate 102 if (traits::post_transform(attr, attr_)) { 103 first = i; 104 return true; 105 } 100 106 } 101 107 102 // do up-stream transformation, this mainly integrates the results 103 // back into the original attribute value, if appropriate 104 traits::post_transform(attr, attr_); 105 return true; 108 transform::fail(attr); 109 return false; 106 110 } 107 111 108 112 template <typename Context> -
boost/spirit/home/support/adapt_adt_attributes.hpp
257 257 { 258 258 return val; 259 259 } 260 static void260 static bool 261 261 post( 262 262 fusion::extension::adt_attribute_proxy<T, N, false>& val 263 263 , Attribute const& attr) 264 264 { 265 265 val = attr; 266 return true; 266 267 } 267 268 static void 268 269 fail(fusion::extension::adt_attribute_proxy<T, N, false>&) … … 289 290 { 290 291 return val; 291 292 } 292 static void293 static bool 293 294 post( 294 295 fusion::extension::adt_attribute_proxy<T, N, Const>& 295 296 , Attribute const&) 296 297 { 298 return true; 297 299 } 298 300 static void 299 301 fail(fusion::extension::adt_attribute_proxy<T, N, Const>&) -
libs/spirit/test/qi/attribute1.cpp
20 20 #include <boost/spirit/include/qi_operator.hpp> 21 21 #include <boost/spirit/include/qi_nonterminal.hpp> 22 22 #include <boost/spirit/include/qi_auxiliary.hpp> 23 #include <boost/spirit/include/qi_directive.hpp> 23 24 24 25 #include <iostream> 25 26 #include <vector> … … 60 61 { 61 62 typedef int type; 62 63 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; } 64 65 static void fail(test_int_data1&) {} 65 66 }; 66 67 }}} … … 80 81 { 81 82 typedef int& type; 82 83 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; } 84 85 static void fail(test_int_data2&) {} 85 86 }; 86 87 }}} 87 88 88 89 /////////////////////////////////////////////////////////////////////////////// 90 struct 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). 98 namespace 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 /////////////////////////////////////////////////////////////////////////////// 89 125 int 90 126 main() 91 127 { … … 173 209 BOOST_TEST(v.size() == 2 && v[0].i == 1 && v[1].i == 2); 174 210 } 175 211 212 // testing controlled failure of attribute transformation 213 { 214 // the parser is expected to fail at the second value 215 std::vector<test_int_data3> v; 216 BOOST_TEST(!test_attr("3,7,2", qi::attr_cast(qi::int_) % ',', v)); 217 BOOST_TEST(v.size() == 1 && v[0].i == 3); 218 219 v.clear(); 220 BOOST_TEST(!test_attr("3,7,2" 221 , qi::attr_cast<test_int_data3>(qi::int_) % ',', v)); 222 BOOST_TEST(v.size() == 1 && v[0].i == 3); 223 224 v.clear(); 225 BOOST_TEST(!test_attr("3,7,2" 226 , qi::attr_cast<test_int_data3, int>(qi::int_) % ',', v)); 227 BOOST_TEST(v.size() == 1 && v[0].i == 3); 228 229 // the parser is expected to hit an alternative and proceed 230 v.clear(); 231 BOOST_TEST(test_attr("3,7,2" 232 , (qi::attr_cast<test_int_data3>(qi::int_) | qi::omit[qi::int_]) % ',', v)); 233 BOOST_TEST(v.size() == 3 && v[0].i == 3 && v[1].i == -1 && v[2].i == 2); 234 } 176 235 return boost::report_errors(); 177 236 } -
libs/spirit/test/qi/attribute2.cpp
60 60 { 61 61 typedef int type; 62 62 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; } 64 64 static void fail(test_int_data1&) {} 65 65 }; 66 66 }}} … … 80 80 { 81 81 typedef int& type; 82 82 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; } 84 84 static void fail(test_int_data2&) {} 85 85 }; 86 86 }}} -
libs/spirit/test/qi/regression_transform_assignment.cpp
31 31 return fusion::tie(parts.second, parts.first); 32 32 } 33 33 34 static void post(foo_parts &, type const &) {}34 static bool post(foo_parts &, type const &) { return true; } 35 35 static void fail(foo_parts &) {} 36 36 }; 37 37 }}} -
libs/spirit/doc/advanced/customization_points.qbk
477 477 typedef <unspecified> type; 478 478 479 479 static type pre(Exposed& val); 480 static voidpost(Exposed& val, type attr); // Qi only480 static bool post(Exposed& val, type attr); // Qi only 481 481 static void fail(Exposed&); // Qi only 482 482 }; 483 483 … … 533 533 as exposed by the metafunction `type`). This function 534 534 will be called in /Qi/ and for /Karma/.]] 535 535 [[ 536 `` voidtransform_attribute<Exposed, Transformed, Domain>::post(exposed, transformed)``]536 ``bool transform_attribute<Exposed, Transformed, Domain>::post(exposed, transformed)``] 537 537 [Do `post`-transformation after the invocation of the 538 538 right hand side component for `rule` (or the embedded 539 539 component for `attr_cast`). This takes the original 540 540 attribute as supplied by the user and the attribute 541 541 as returned from the right hand side (embedded) 542 542 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.]] 545 547 [[ 546 548 ``void transform_attribute<Exposed, Transformed, Domain>::fail(exposed)``] 547 549 [Handling failing parse operations of the -
libs/spirit/doc/qi/auxiliary.qbk
217 217 218 218 [reference_qi_attr_cast1] 219 219 220 [heading Advanced Example] 221 222 Just like semantic actions, __customize_transform_attribute__ has the ability 223 to signal failure back to the parser. This may happen if there's no obvious 224 way to convert the parsed attribute value back to the exposed attribute type. 225 Common examples of such behavior are enumerations and range restricted 226 arithmetic types, but, of course, other similar use cases are also possible. 227 228 Lets 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 233 Now we can attempt to parse some values which may not necessarily fit into 234 a range limited type we defined: 235 236 [reference_qi_attr_cast2] 237 238 The full cpp file for this example can be found here: [@../../example/qi/attr_cast.cpp] 239 220 240 [endsect] 221 241 222 242 -
libs/spirit/example/qi/Jamfile
36 36 exe boost_array : boost_array.cpp ; 37 37 exe display_attribute_type : display_attribute_type.cpp ; 38 38 exe adapt_template_struct : adapt_template_struct.cpp ; 39 exe attr_cast : attr_cast.cpp ; 39 40 40 41 exe unescaped_string : unescaped_string.cpp ; 41 42 -
libs/spirit/example/qi/reference.cpp
292 292 { 293 293 typedef int& type; 294 294 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; } 296 297 static void fail(int_data&) {} 297 298 }; 298 299 }}} -
libs/spirit/example/qi/parse_date.cpp
54 54 // We need to initialize the attribute supplied to the rule (referenced 55 55 // by the first argument) with the values taken from the parsing 56 56 // results (referenced by the second argument). 57 static voidpost(boost::gregorian::date& d, date_parts const& v)57 static bool post(boost::gregorian::date& d, date_parts const& v) 58 58 { 59 59 d = boost::gregorian::date(fusion::at_c<0>(v), fusion::at_c<1>(v) 60 60 , fusion::at_c<2>(v)); 61 return true; 61 62 } 62 63 63 64 // The function fail() is called whenever the parsing of the right hand -
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 12 namespace qi = boost::spirit::qi; 13 namespace fusion = boost::fusion; 14 15 template <typename P, typename T> 16 void 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. 32 struct less_than_100 33 { 34 int i; 35 }; 36 37 // Counter variable we shall use later on. 38 int greater_than_100_cnt = 0; 39 40 // Custom attribute transformations for our primitive range restricted type. 41 namespace 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 69 namespace 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 /////////////////////////////////////////////////////////////////////////////// 87 int 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 } -
libs/spirit/example/qi/adapt_template_struct.cpp
44 44 typedef fusion::vector<A&, B&> type; 45 45 46 46 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; } 48 48 static void fail(client::data<A, B>&) {} 49 49 }; 50 50 }}} -
libs/spirit/example/support/utree/sexpr_parser.hpp
21 21 typedef unused_type type; 22 22 23 23 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; } 25 25 static void fail (utree::nil_type&) { } 26 26 }; 27 27