@@ -171,8 +171,112 @@ the supplied string.
171
171
Parses the contents of the file C < $filename > with the L < parse > method,
172
172
passing any named options in C < %opts > .
173
173
174
- = head1 Action Classes
174
+ = head1 Action Objects
175
175
176
- TODO
176
+ A successful grammar match gives you a parse tree of L < Match|/type/Match >
177
+ objects, and the deeper that match tree gets, and the more branches in the
178
+ grammar are, the harder it becomes to navigate the match tree to get the
179
+ information you are actually interested in.
180
+
181
+ To avoid the need for diving deep into a match tree, you can supply an
182
+ I < actions > object. After each successful parse of a named rule in your
183
+ grammar, it tries to call a method of the same name as the grammar rule,
184
+ giving it the newly create L < Match|/type/Match > object as a positional
185
+ argument. If no such method exists, it is skipped.
186
+
187
+ Here is a contrieved example of a grammar and actions in action:
188
+
189
+ = begin code
190
+ use v6;
191
+
192
+ grammar TestGrammar {
193
+ token TOP { ^ \d+ $ }
194
+ }
195
+
196
+ class TestActions {
197
+ method TOP($/) {
198
+ $/.make(2 + ~$/);
199
+ }
200
+ }
201
+
202
+ my $actions = TestActions.new;
203
+ my $match = TestGrammar.parse('40', :$actions);
204
+ say $match; # 「40」
205
+ say $match.made; # 42
206
+ = end code
207
+
208
+ An instance of C < TestActions > is passed as named argument C < actions > to the
209
+ L < parse|/type/Grammar|method parse > call, and when token C < TOP > has matched
210
+ successfully, it automatically calls method C < TOP > , passing the match object
211
+ as an argument.
212
+
213
+ To make it clear that the argument is a match object, the example uses C < $/ >
214
+ as a parameter name to the action method, though that's just a handy
215
+ convention, notthing intrinsic. C < $match > would have worked too. (Though using
216
+ C < $/ > does give the advantage of providing C << $<capture> >> > as a shortcut
217
+ for C << $/<capture> >> ).
218
+
219
+ A slightly more involved example follows:
220
+
221
+ = begin code
222
+ use v6;
223
+
224
+ grammar KeyValuePairs {
225
+ token TOP {
226
+ [<pair> \n+]*
227
+ }
228
+ token ws { \h* }
229
+
230
+ rule pair {
231
+ <key=.identifier> '=' <value=.identifier>
232
+ }
233
+ token identifier {
234
+ \w+
235
+ }
236
+ }
237
+
238
+ class KeyValuePairsActions {
239
+ method identifier($/) { $/.make: ~$/ }
240
+ method pair ($/) { $/.make: $<key>.made => $<value>.made }
241
+ method TOP ($/) { $/.make: $<pair>».made }
242
+ }
243
+
244
+ my $res = KeyValuePairs.parse(q:to/EOI/, :actions(KeyValuePairsActions)).made;
245
+ second=b
246
+ hits=42
247
+ perl=6
248
+ EOI
249
+
250
+ for @$res -> $p {
251
+ say "Key: $p.key()\tValue: $p.value()";
252
+ }
253
+ = end code
254
+
255
+ This produces the following ouput:
256
+
257
+ = begin code
258
+ Key: second Value: b
259
+ Key: hits Value: 42
260
+ Key: perl Value: 6
261
+ = end code
262
+
263
+ Rule C < pair > , which parsed a pair separated by an equals sign, aliases the two
264
+ calls to token C < identifier > to separate capture names to make them available
265
+ more easily and intuitively. The corresponding action method constructs a
266
+ L < Pair|/type/Pair > object, and uses the C < .made > property of the sub match
267
+ objects. So it (like the action method C < TOP > too) exploits the fact that
268
+ action methods for submatches are called before those of the calling/outer
269
+ regex. So action methods are called in
270
+ L < post-order|https://en.wikipedia.org/wiki/Tree_traversal#Post-order > .
271
+
272
+ The action method C < TOP > simply collects all the objects that were C < .made > by
273
+ the multiple matches of the C < pair > rule, and returns them in a list.
274
+
275
+ Also note that C < KeyValuePairsActions > was passed as a type object to method
276
+ C < parse > , which was possible because none of the action methods use attributes
277
+ (which would only be available in an instance).
278
+
279
+ In other cases, action methods might want to keep state in attributes. Then of
280
+ course you must pass an instance to method parse.
177
281
178
282
= end pod
0 commit comments