1[/============================================================================== 2 Copyright (C) 2001-2010 Joel de Guzman 3 Copyright (C) 2001-2005 Dan Marsden 4 Copyright (C) 2001-2010 Thomas Heller 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8===============================================================================/] 9 10[section Statement] 11 12[*/Lazy statements.../] 13 14The expressions presented so far are sufficiently 15powerful to construct quite elaborate structures. We have presented lazy-functions 16and lazy-operators. How about lazy-statements? First, an appetizer: 17 18Print all odd-numbered contents of an STL container using `std::for_each` 19([@../../example/all_odds.cpp all_odds.cpp]): 20 21 std::for_each(c.begin(), c.end(), 22 if_(arg1 % 2 == 1) 23 [ 24 cout << arg1 << ' ' 25 ] 26 ); 27 28Huh? Is that valid C++? Read on... 29 30Yes, it is valid C++. The sample code above is as close as you can get to the 31syntax of C++. This stylized C++ syntax differs from actual C++ code. First, the 32`if` has a trailing underscore. Second, the block uses square brackets instead 33of the familiar curly braces {}. 34 35[note *C++ in C++?* 36 37 In as much as __spirit__ attempts to mimic EBNF in C++, 38 Phoenix attempts to mimic C++ in C++!!! 39] 40 41[note Unlike lazy functions and lazy operators, lazy statements always 42return void.] 43 44Here are more examples with annotations. The code almost speaks for itself. 45 46[section Block Statement] 47 48[/ #include <boost/phoenix/statement/sequence.hpp>] 49 50Syntax: 51 52 statement, 53 statement, 54 .... 55 statement 56 57Basically, these are comma separated statements. Take note that unlike the C/C++ 58semicolon, the comma is a separator put *in-between* statements. This is like 59Pascal's semicolon separator, rather than C/C++'s semicolon terminator. For 60example: 61 62 statement, 63 statement, 64 statement, // ERROR! 65 66Is an error. The last statement should not have a comma. Block statements can be 67grouped using the parentheses. Again, the last statement in a group should not 68have a trailing comma. 69 70 statement, 71 statement, 72 ( 73 statement, 74 statement 75 ), 76 statement 77 78Outside the square brackets, block statements should be grouped. For example: 79 80 std::for_each(c.begin(), c.end(), 81 ( 82 do_this(arg1), 83 do_that(arg1) 84 ) 85 ); 86 87Wrapping a comma operator chain around a parentheses pair blocks the 88interpretation as an argument separator. The reason for the exception for 89the square bracket operator is that the operator always takes exactly one 90argument, so it "transforms" any attempt at multiple arguments with a comma 91operator chain (and spits out an error for zero arguments). 92 93[endsect] 94 95[section if_ Statement] 96 97 #include <boost/phoenix/statement/if.hpp> 98 99We have seen the `if_` statement. The syntax is: 100 101 if_(conditional_expression) 102 [ 103 sequenced_statements 104 ] 105 106[endsect] 107 108[section '''if_else_''' Statement] 109 110 #include <boost/phoenix/statement/if.hpp> 111 112The syntax is 113 114 if_(conditional_expression) 115 [ 116 sequenced_statements 117 ] 118 .else_ 119 [ 120 sequenced_statements 121 ] 122 123Take note that `else` has a leading dot and a trailing underscore: `.else_` 124 125Example: This code prints out all the elements and appends `" > 5"`, `" == 5"` 126or `" < 5"` depending on the element's actual value: 127 128 std::for_each(c.begin(), c.end(), 129 if_(arg1 > 5) 130 [ 131 cout << arg1 << " > 5\n" 132 ] 133 .else_ 134 [ 135 if_(arg1 == 5) 136 [ 137 cout << arg1 << " == 5\n" 138 ] 139 .else_ 140 [ 141 cout << arg1 << " < 5\n" 142 ] 143 ] 144 ); 145 146Notice how the `if_else_` statement is nested. 147 148[/note `if_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details] 149 150[endsect] 151 152[section switch_ Statement] 153 154 #include <boost/phoenix/statement/switch.hpp> 155 156The syntax is: 157 158 switch_(integral_expression) 159 [ 160 case_<integral_value>(sequenced_statements), 161 ... 162 default_(sequenced_statements) 163 ] 164 165A comma separated list of cases, and an optional default can be provided. Note unlike 166a normal switch statement, cases do not fall through. 167 168Example: This code prints out `"one"`, `"two"` or `"other value"` depending on the 169element's actual value: 170 171 std::for_each(c.begin(), c.end(), 172 switch_(arg1) 173 [ 174 case_<1>(std::cout << val("one") << '\n'), 175 case_<2>(std::cout << val("two") << '\n'), 176 default_(std::cout << val("other value") << '\n') 177 ] 178 ); 179 180[endsect] 181 182[section while_ Statement] 183 184 #include <boost/phoenix/statement/while.hpp> 185 186The syntax is: 187 188 while_(conditional_expression) 189 [ 190 sequenced_statements 191 ] 192 193Example: This code decrements each element until it reaches zero and prints out 194the number at each step. A newline terminates the printout of each value. 195 196 std::for_each(c.begin(), c.end(), 197 ( 198 while_(arg1--) 199 [ 200 cout << arg1 << ", " 201 ], 202 cout << val("\n") 203 ) 204 ); 205 206[endsect] 207 208[section '''do_while_''' Statement] 209 210 #include <boost/phoenix/statement/do_while.hpp> 211 212The syntax is: 213 214 do_ 215 [ 216 sequenced_statements 217 ] 218 .while_(conditional_expression) 219 220Again, take note that `while` has a leading dot and a trailing underscore: 221`.while_` 222 223Example: This code is almost the same as the previous example above with a 224slight twist in logic. 225 226 std::for_each(c.begin(), c.end(), 227 ( 228 do_ 229 [ 230 cout << arg1 << ", " 231 ] 232 .while_(arg1--), 233 cout << val("\n") 234 ) 235 ); 236 237[/note `do_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details] 238 239[endsect] 240 241[section:for_statement for_ Statement] 242 243 #include <boost/phoenix/statement/for.hpp> 244 245The syntax is: 246 247 for_(init_statement, conditional_expression, step_statement) 248 [ 249 sequenced_statements 250 ] 251 252It is again very similar to the C++ for statement. Take note that the 253init_statement, conditional_expression and '''step_statement''' are separated by the 254comma instead of the semi-colon and each must be present (i.e. `for_(,,)` is 255invalid). This is a case where the [link phoenix.modules.core.nothing `nothing`] 256actor can be useful. 257 258Example: This code prints each element N times where N is the element's value. A 259newline terminates the printout of each value. 260 261 int iii; 262 std::for_each(c.begin(), c.end(), 263 ( 264 for_(ref(iii) = 0, ref(iii) < arg1, ++ref(iii)) 265 [ 266 cout << arg1 << ", " 267 ], 268 cout << val("\n") 269 ) 270 ); 271 272As before, all these are lazily evaluated. The result of such statements are in 273fact expressions that are passed on to STL's for_each function. In the viewpoint 274of `for_each`, what was passed is just a functor, no more, no less. 275 276[endsect] 277 278[section try_ catch_ Statement] 279 280 #include <boost/phoenix/statement/try_catch.hpp> 281 282The syntax is: 283 284 try_ 285 [ 286 sequenced_statements 287 ] 288 .catch_<exception_type>() 289 [ 290 sequenced_statements 291 ] 292 .catch_<another_exception_type>(local-id) 293 [ 294 sequenced_statements 295 ] 296 ... 297 .catch_all 298 [ 299 sequenced_statement 300 ] 301 302Note the usual underscore after try and catch, and the extra parentheses required 303after the catch. 304 305The second form of catch statement can refer thrown exception using specified 306local-id, which is __phoenix_local_variable__, in sequenced_statements. 307 308[/note `do_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details] 309 310Example: The following code calls the (lazy) function `f` for each element, and 311prints messages about different exception types it catches. 312 313 try_ 314 [ 315 f(arg1) 316 ] 317 .catch_<runtime_error>() 318 [ 319 cout << val("caught runtime error or derived\n") 320 ] 321 .catch_<exception>(e_) 322 [ 323 cout << val("caught exception or derived: ") << bind(&exception::what, e_) << val("\n") 324 ] 325 .catch_all 326 [ 327 cout << val("caught some other type of exception\n") 328 ] 329 330[endsect] 331 332[section throw_] 333 334 #include <boost/phoenix/statement/throw.hpp> 335 336As a natural companion to the try/catch support, the statement module provides 337lazy throwing and re-throwing of exceptions. 338 339The syntax to throw an exception is: 340 341 throw_(exception_expression) 342 343The syntax to re-throw an exception is: 344 345 throw_() 346 347Example: This code extends the try/catch example, re-throwing exceptions derived from 348runtime_error or exception, and translating other exception types to runtime_errors. 349 350 try_ 351 [ 352 f(arg1) 353 ] 354 .catch_<runtime_error>() 355 [ 356 cout << val("caught runtime error or derived\n"), 357 throw_() 358 ] 359 .catch_<exception>() 360 [ 361 cout << val("caught exception or derived\n"), 362 throw_() 363 ] 364 .catch_all 365 [ 366 cout << val("caught some other type of exception\n"), 367 throw_(runtime_error("translated exception")) 368 ] 369 370[endsect] 371 372[endsect] 373