• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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