File Coverage

blib/lib/Pugs/Emitter/Rule/Perl5.pm
Criterion Covered Total %
statement 15 239 6.2
branch 0 142 0.0
condition 0 39 0.0
subroutine 5 31 16.1
pod 0 26 0.0
total 20 477 4.1


line stmt bran cond sub pod time code
1             package Pugs::Emitter::Rule::Perl5;
2              
3 17     17   179703 use Pugs::Emitter::Rule::Perl5::Ratchet;
  17         69  
  17         1268  
4              
5             # p6-rule perl5 emitter
6              
7 17     17   216 use strict;
  17         40  
  17         952  
8 17     17   126 use warnings;
  17         1187  
  17         833  
9 17     17   195 use Data::Dumper;
  17         39  
  17         13523  
10             $Data::Dumper::Indent = 1;
11              
12             our $capture_count;
13             our $capture_to_array;
14             our %capture_seen;
15              
16             sub call_subrule {
17 0     0 0   my ( $subrule, $tab, $positionals, @param ) = @_;
18 0 0         $subrule = "\$_[4]->" . $subrule unless $subrule =~ / :: | \. | -> /x;
19 0           $subrule =~ s/\./->/; # XXX - source filter
20              
21 0 0 0       $positionals = shift @param if $positionals eq '' && @param == 1; # odd number of elements in hash
22             #print "PARAM: ",Dumper(@param);
23              
24             return
25 0           "$tab sub{
26             $tab my \$prior = \$::_V6_PRIOR_;
27             $tab my \$param = { \%{ \$_[7] || {} }, positionals => [ $positionals ], args => {" .
28             join(", ",@param) . "} };
29             $tab \$_[3] = $subrule( \$_[0], \$param, \$_[3], );
30             $tab \$::_V6_PRIOR_ = \$prior;
31             $tab }
32             ";
33             }
34              
35             sub call_subrule_no_capture {
36 0     0 0   my ( $subrule, $tab, $positionals, @param ) = @_;
37 0 0         $subrule = "\$_[4]->" . $subrule unless $subrule =~ / :: | \. | -> /x;
38 0           $subrule =~ s/\./->/; # XXX - source filter
39              
40 0 0 0       $positionals = shift @param if $positionals eq '' && @param == 1; # odd number of elements in hash
41             #print "PARAM: ",Dumper(@param);
42              
43             return
44 0           "$tab sub{
45             $tab my \$prior = \$::_V6_PRIOR_;
46             $tab my \$param = { \%{ \$_[7] || {} }, positionals => [ $positionals ], args => {" .
47             join(", ",@param) . "} };
48             $tab \$_[3] = $subrule( \$_[0], \$param, \$_[3], );
49             $tab \$_[3]->data->{match} = [];
50             $tab \$_[3]->data->{named} = {};
51             $tab \$::_V6_PRIOR_ = \$prior;
52             $tab }
53             ";
54             }
55              
56             sub emit {
57 0     0 0   my ($grammar, $ast) = @_;
58             # runtime parameters: $grammar, $string, $state, $arg_list
59             # rule parameters: see Runtime::Rule.pm
60 0           local $capture_count = -1;
61 0           local $capture_to_array = 0;
62 0           local %capture_seen = ();
63             #print "emit capture_to_array $capture_to_array\n";
64             # print "emit: ", Dumper($ast);
65             #die emit_rule( $ast, ' ' );
66              
67             return
68 0           "do {
69             package Pugs::Runtime::Regex;
70             my \$matcher = \n" . emit_rule( $ast, ' ' ) . ";
71             my \$rule;
72             \$rule = sub {" .
73             # grammar, string, state, args
74             #" print \"match args: \",Dumper(\@_);\n" .
75             "
76             my \$tree;
77             if ( defined \$_[3]{p}
78             && ! \$_[3]{continue}
79             ) {
80             \$matcher->( \$_[1], \$_[2], \$tree, \$tree, \$_[0], \$_[3]{p}, \$_[1], \$_[3] );
81             }
82             else {
83             \$_[3]{p} ||= 0;
84             for my \$pos ( \$_[3]{p} .. length( \$_[1] ) ) {
85             my \$param = { \%{\$_[3]}, p => \$pos };
86             \$matcher->( \$_[1], \$_[2], \$tree, \$tree, \$_[0], \$pos, \$_[1], \$param );
87             last if \$tree;
88             }
89             \$tree = Pugs::Grammar::Base->no_match(\@_)
90             unless defined \$tree;
91             }
92             my \$cap = \$tree->data->{capture};
93             if ( ref \$cap eq 'CODE' ) {
94             \$::_V6_MATCH_ = \$tree;
95             \$tree->data->{capture} = \\(\$cap->( \$tree ));
96             };
97             if ( \$tree ) {
98             # \$::_V6_PRIOR_ = \$rule
99              
100             my \$prior = \$::_V6_PRIOR_;
101             \$::_V6_PRIOR_ = sub {
102             local \$main::_V6_PRIOR_ = \$prior;
103             \$rule->(\@_);
104             };
105              
106             }
107             return \$tree;
108             }
109             }
110             ";
111             }
112              
113             sub emit_rule {
114 0     0 0   my $n = $_[0];
115 0           my $tab = $_[1] . ' ';
116 0 0         die "unknown node: ", Dumper( $n )
117             unless ref( $n ) eq 'HASH';
118             #print "NODE ", Dumper($n);
119 0           my @keys = grep { substr($_, 0, 1) ne '_' } keys %$n;
  0            
120 0           my ($k) = @keys;
121 0           my $v = $$n{$k};
122             # XXX - use real references
123 17     17   123 no strict 'refs';
  17         37  
  17         82229  
124 0           my $code = &$k( $v, $tab );
125 0           return $code;
126             }
127              
128             #rule nodes
129              
130             sub capturing_group {
131 0     0 0   my $program = $_[0];
132              
133 0           $capture_count++;
134             {
135 0           $capture_seen{$capture_count}++;
  0            
136 0           local $capture_count = -1;
137 0           local $capture_to_array = 0;
138 0           local %capture_seen = ();
139 0 0         $program = emit_rule( $program, $_[1].' ' )
140             if ref( $program );
141             }
142              
143             return
144 0   0       "$_[1] positional( $capture_count, " .
145             ( $capture_to_array || ( $capture_seen{$capture_count} > 1 ? 1 : 0 ) ) .
146             ", \n" .
147             $program .
148             "$_[1] )\n";
149             }
150             sub capture_as_result {
151 0     0 0   my $program = $_[0];
152              
153 0           $capture_count++;
154             {
155 0           $capture_seen{$capture_count}++;
  0            
156 0           local $capture_count = -1;
157 0           local $capture_to_array = 0;
158 0           local %capture_seen = ();
159 0 0         $program = emit_rule( $program, $_[1].' ' )
160             if ref( $program );
161             }
162              
163             return
164 0           "$_[1] capture_as_result( \n" .
165             $program .
166             "$_[1] )\n";
167             }
168             sub non_capturing_group {
169 0     0 0   return emit_rule( $_[0], $_[1] );
170             }
171             sub quant {
172 0     0 0   my $term = $_[0]->{'term'};
173 0   0       my $quantifier = $_[0]->{quant} || '';
174 0   0       my $greedy = $_[0]->{greedy} || ''; # + ?
175              
176 0 0         if ( ref( $quantifier ) eq 'HASH' )
177             {
178 0           die "quantifier not implemented: " . Dumper( $quantifier );
179              
180             #return
181             # "$_[1] concat(\n" .
182             # join( ',', ($rul) x $count ) .
183             # "$_[1] )\n";
184             }
185              
186 0           my $quant = $quantifier . $greedy;
187 0           my $sub = {
188             '*' =>'greedy_star',
189             '+' =>'greedy_plus',
190             '*?'=>'non_greedy_star',
191             '+?'=>'non_greedy_plus',
192             '?' =>'optional',
193             '??'=>'null_or_optional',
194             '' => '',
195             }->{$quant};
196 0 0         die "quantifier not implemented: $quant"
197             unless defined $sub;
198              
199 0           my $rul;
200             {
201 0           my $cap = $capture_to_array;
  0            
202 0   0       local $capture_to_array = $cap || ( $quant ne '' ? 1 : 0 );
203 0           $rul = emit_rule( $term, $_[1] . ' ' );
204             }
205              
206 0 0         return $rul
207             if $sub eq '';
208             return
209 0           "$_[1] $sub(\n" .
210             $rul .
211             "$_[1] )\n";
212             }
213             sub alt {
214 0     0 0   my @s;
215             # print "Alt: ", Dumper($_[0]);
216 0           my $count = $capture_count;
217 0           my $max = -1;
218 0           for ( @{$_[0]} ) {
  0            
219 0           $capture_count = $count;
220              
221 0           my $_capture_count = $capture_count;
222 0           my $_capture_to_array = $capture_to_array;
223 0           my %_capture_seen = ( %capture_seen );
224 0           local $capture_count = $_capture_count;
225 0           local $capture_to_array = $_capture_to_array;
226 0           local %capture_seen = ( %_capture_seen );
227              
228 0           my $tmp = emit_rule( $_, $_[1].' ' );
229             # print ' ',$capture_count;
230 0 0         $max = $capture_count
231             if $capture_count > $max;
232 0 0         push @s, $tmp if $tmp;
233             }
234 0           $capture_count = $max;
235              
236 0           return "$_[1] alternation( [\n" .
237             join( ',', @s ) .
238             "$_[1] ] )\n";
239             }
240 0     0 0   sub alt1 { &alt }
241             sub concat {
242 0     0 0   my @s;
243 0           for ( @{$_[0]} ) {
  0            
244 0           my $tmp = emit_rule( $_, $_[1] );
245 0 0         push @s, $tmp if $tmp;
246             }
247             return
248 0           "$_[1] concat( \n" .
249             join( ',', @s ) .
250             "$_[1] )\n";
251             }
252             sub code {
253 0     0 0   return "$_[1] $_[0]\n";
254             }
255             sub dot {
256 0     0 0   return call_subrule( 'any', $_[1], '' );
257             }
258             sub variable {
259 0     0 0   my $name = "$_[0]";
260 0           my $value = undef;
261             # XXX - eval $name doesn't look up in user lexical pad
262             # XXX - what &xxx interpolate to?
263              
264 0 0         if ( $name =~ /^\$/ ) {
265             # $^a, $^b
266 0 0         if ( $name =~ /^ \$ \^ ([^\s]*) /x ) {
267 0           my $index = ord($1)-ord('a');
268             #print "Variable #$index\n";
269             #return "$_[1] constant( \$_[7][$index] )\n";
270              
271 0           my $code =
272             " sub {
273             #print \"Runtime Variable args[\", join(\",\",\@_) ,\"] \$_[7][$index]\\n\";
274             return constant( \$_[7][$index] )->(\@_);
275             }";
276 0           $code =~ s/^/$_[1]/mg;
277 0           return "$code\n";
278             }
279             else {
280 0           $value = eval $name;
281             }
282             }
283              
284             # ??? $value = join('', eval $name) if $name =~ /^\@/;
285              
286 0 0         if ( $name =~ /^%/ ) {
287             # XXX - runtime or compile-time interpolation?
288 0 0         return "$_[1] hash( \\$name )\n" if $name =~ /::/;
289 0           return "$_[1] hash( get_variable( '$name' ) )\n";
290             }
291 0 0         die "interpolation of $name not implemented"
292             unless defined $value;
293              
294 0           return "$_[1] constant( '" . $value . "' )\n";
295             }
296             sub special_char {
297 0     0 0   my ($char, $data) = $_[0] =~ /^.(.)(.*)/;
298 0 0         $_[1] = '' unless defined $_[1];
299              
300 0 0         return "$_[1] perl5( '\\N{" . join( "}\\N{", split( /\s*;\s*/, $data ) ) . "}' )\n"
301             if $char eq 'c';
302 0 0         return "$_[1] perl5( '(?!\\N{" . join( "}\\N{", split( /\s*;\s*/, $data ) ) . "})\\X' )\n"
303             if $char eq 'C';
304              
305 0 0         return "$_[1] perl5( '\\x{$data}' )\n"
306             if $char eq 'x';
307 0 0         return "$_[1] perl5( '(?!\\x{$data})\\X' )\n"
308             if $char eq 'X';
309              
310 0 0         return special_char( sprintf("\\x%X", oct($data) ) )
311             if $char eq 'o';
312 0 0         return special_char( sprintf("\\X%X", oct($data) ) )
313             if $char eq 'O';
314              
315 0 0         return "$_[1] perl5( '(?:\\n\\r?|\\r\\n?|\\x85|\\x{2028})' )\n"
316             if $char eq 'n';
317 0 0         return "$_[1] perl5( '(?!\\n\\r?|\\r\\n?|\\x85|\\x{2028})\\X' )\n"
318             if $char eq 'N';
319              
320             # XXX - Infinite loop in pugs stdrules.t
321             #return metasyntax( '?_horizontal_ws', $_[1] )
322 0 0         return "$_[1] perl5( '[\\x20\\x09]' )\n"
323             if $char eq 'h';
324 0 0         return "$_[1] perl5( '[^\\x20\\x09]' )\n"
325             if $char eq 'H';
326             #return metasyntax( '?_vertical_ws', $_[1] )
327 0 0         return "$_[1] perl5( '[\\x0A\\x0D]' )\n"
328             if $char eq 'v';
329 0 0         return "$_[1] perl5( '[^\\x0A\\x0D]' )\n"
330             if $char eq 'V';
331              
332 0           for ( qw( r n t e f w d s ) ) {
333 0 0         return "$_[1] perl5( '\\$_' )\n" if $char eq $_;
334 0 0         return "$_[1] perl5( '[^\\$_]' )\n" if $char eq uc($_);
335             }
336 0 0         $char = '\\\\' if $char eq '\\';
337 0 0         return "$_[1] constant( q!$char! )\n" unless $char eq '!';
338 0           return "$_[1] constant( q($char) )\n";
339             }
340             sub match_variable {
341 0     0 0   my $name = $_[0];
342 0           my $num = substr($name,1);
343             #print "var name: ", $num, "\n";
344 0           my $code =
345             " sub {
346             my \$m = \$_[2];
347             #print 'var: ',\$m->perl;
348             #print 'var: ',\$m->[$num];
349             return constant( \"\$m->[$num]\" )->(\@_);
350             }";
351 0           $code =~ s/^/$_[1]/mg;
352 0           return "$code\n";
353             }
354             sub closure {
355 0     0 0   my $code = $_[0]{closure};
356 0           my $modifier = $_[0]{modifier}; # 'plain', '', '?', '!'
357              
358             #die "closure modifier not implemented '$modifier'"
359             # unless $modifier eq 'plain';
360              
361             #warn "CODE $code";
362 0 0         $code = '' if $code eq '{*}'; # "whatever"
363              
364 0 0 0       if ( ref( $code )
365             && defined $Pugs::Compiler::Perl6::VERSION
366             ) {
367             # perl6 compiler is loaded
368 0           $code = Pugs::Emitter::Perl6::Perl5::emit( 'grammar', $code, 'self' );
369 0           $code = '{ my $_V6_SELF = shift; ' . $code . '}'; # make it a "method"
370             }
371             else {
372             # XXX XXX XXX - source-filter - temporary hacks to translate p6 to p5
373             # $()
374 0           $code =~ s/ ([^']) \$ \( \) < (.*?) > /$1 \$_[0]->[$2]/sgx;
375             # $
376 0           $code =~ s/ ([^']) \$ < (.*?) > /$1 \$_[0]->{$2}/sgx;
377             # $()
378 0           $code =~ s/ ([^']) \$ \( \) /$1 \$_[0]->()/sgx;
379             # $/
380 0           $code =~ s/ ([^']) \$ \/ /$1 \$_[0]/sgx;
381             }
382             #print "Code: $code\n";
383              
384 0 0         return "
385             sub {
386             \$_[3] = Pugs::Runtime::Match->new( {
387             bool => \\1,
388             str => \\(\$_[0]),
389             from => \\(\$_[7]{p} || 0),
390             to => \\(\$_[7]{p} || 0),
391             match => [],
392             named => {},
393             capture => sub { $code },
394             abort => 1,
395             } )
396             }\n"
397             if $code =~ /return/;
398              
399 0           my $bool = "\\\$::_V6_SUCCEED";
400 0 0         $bool = "\\( \$capture ? 1 : 0 )" if $modifier eq '?';
401 0 0         $bool = "\\( \$capture ? 0 : 1 )" if $modifier eq '!';
402              
403 0           my $cap = "\\\$capture";
404 0 0 0       $cap = "undef" if $modifier eq '?' || $modifier eq '!';
405              
406 0           return "
407             sub {
408             \$::_V6_MATCH_ = \$_[0];
409             local \$::_V6_SUCCEED = 1;
410             my \$capture = sub { $code }->( \$_[3] );
411             \$_[3] = Pugs::Runtime::Match->new( {
412             bool => $bool,
413             str => \\(\$_[0]),
414             from => \\(\$_[7]{p} || 0),
415             to => \\(\$_[7]{p} || 0),
416             match => [],
417             named => {},
418             capture => undef,
419             } )
420             }\n";
421              
422             }
423             sub named_capture {
424 0     0 0   my $name = $_[0]{ident};
425 0 0         $name = $name->{match_variable} if ref($name) eq 'HASH';
426 0           $name =~ s/^[\$\@\%]//; # TODO - change semantics as needed
427 0           my $program = $_[0]{rule};
428 0           $capture_seen{$name}++;
429             return
430 0   0       "$_[1] named( '$name', " .
431             ( $capture_to_array || ( $capture_seen{$name} > 1 ? 1 : 0 ) ) .
432             ", \n" .
433             emit_rule($program, $_[1]) .
434             "$_[1] )\n";
435             }
436             sub negate {
437 0     0 0   my $program = $_[0];
438             #print "Negate: ", Dumper($_[0]);
439             return
440 0           "$_[1] negate( \n" .
441             emit_rule($program, $_[1]) .
442             "$_[1] )\n";
443             }
444             sub before {
445 0     0 0   my $program = $_[0]{rule};
446             return
447 0           "$_[1] before( \n" .
448             emit_rule($program, $_[1]) .
449             "$_[1] )\n";
450             }
451             sub colon {
452 0     0 0   my $str = $_[0];
453 0 0         return "$_[1] at_start() \n"
454             if $str eq '^';
455 0 0         return "$_[1] alternation( [ null(), failed_abort() ] ) \n"
456             if $str eq ':';
457 0 0         return "$_[1] at_end_of_string() \n"
458             if $str eq '$';
459 0 0         return "$_[1] at_line_start() \n"
460             if $str eq '^^';
461 0 0         return "$_[1] at_line_end() \n"
462             if $str eq '$$';
463 0 0         return metasyntax( '?_wb_left', $_[1] )
464             if $str eq '<<';
465 0 0         return metasyntax( '?_wb_right', $_[1] )
466             if $str eq '>>';
467 0           die "'$str' not implemented";
468             }
469             sub modifier {
470 0     0 0   my $str = $_[0]{modifier};
471 0           my $rule = $_[0]{rule};
472              
473 0 0         return "$_[1] ignorecase( \n"
474             . emit_rule( $rule, $_[1] . ' ' )
475             . " )\n"
476             if $str eq 'ignorecase';
477              
478 0           die "modifier '$str' not implemented";
479             }
480             sub constant {
481 0 0   0 0   my $char = $_[0] eq '\\' ? '\\\\' : $_[0];
482 0 0         return "$_[1] constant( q!$char! )\n" unless $char =~ /!/;
483 0           return "$_[1] constant( q($char) )\n";
484             }
485             sub char_class {
486 0     0 0   my $cmd = Pugs::Emitter::Rule::Perl5::CharClass::emit( $_[0] );
487 0 0         return "$_[1] perl5( q!$cmd! )\n" unless $cmd =~ /!/;
488 0           return "$_[1] perl5( q($cmd) )\n"; # XXX if $cmd eq '!)'
489             }
490             sub call {
491             #die "not implemented: ", Dumper(\@_);
492 0     0 0   my $param = $_[0]{params};
493 0           my $name = $_[0]{method};
494             # capturing subrule
495             #
496 0           my ($param_list) = $param =~ /\{(.*)\}/;
497 0 0         $param_list = '' unless defined $param_list;
498 0           my @param = split( ',', $param_list );
499 0           $capture_seen{$name}++;
500             #print "subrule ", $capture_seen{$name}, "\n";
501             #print "param: ", Dumper(\@param);
502             return
503 0   0       "$_[1] named( '$name', " .
504             ( $capture_to_array || ( $capture_seen{$name} > 1 ? 1 : 0 ) ) .
505             ", \n" .
506             call_subrule( $name, $_[1]." ", "", @param ) .
507             "$_[1] )\n";
508             }
509             sub metasyntax {
510 0     0 0   my $cmd = $_[0]{metasyntax};
511 0   0       my $modifier = delete $_[0]{modifier} || ''; # ? !
512 0 0         return negate( { metasyntax => $_[0] }, $_[1] ) if $modifier eq '!';
513              
514 0           my $prefix = substr( $cmd, 0, 1 );
515 0 0         if ( $prefix eq '@' ) {
516             # XXX - wrap @array items - see end of Pugs::Grammar::Rule
517             return
518 0           "$_[1] alternation( \\$cmd )\n";
519             }
520              
521 0 0         if ( $prefix eq '%' ) {
522             # XXX - runtime or compile-time interpolation?
523 0           my $name = substr( $cmd, 1 );
524 0           $capture_seen{$name}++;
525 0 0 0       return "$_[1] named( '$name', " .
526             ( $capture_to_array || ( $capture_seen{$name} > 1 ? 1 : 0 ) ) .
527             ", hash( \\$cmd ) )\n"
528             if $cmd =~ /::/;
529 0   0       return "$_[1] named( '$name', " .
530             ( $capture_to_array || ( $capture_seen{$name} > 1 ? 1 : 0 ) ) .
531             ", hash( get_variable( '$cmd' ) ) )\n";
532             }
533              
534 0 0         if ( $prefix eq '$' ) {
535 0 0         if ( $cmd =~ /::/ ) {
536             # call method in fully qualified $package::var
537             return
538 0           "$_[1] sub { \n" .
539             # "$_[1] print 'params: ',Dumper(\@_);\n" .
540             "$_[1] \$_[3] = $cmd->match( \$_[0], \$_[4], \$_[7], \$_[1] );\n" .
541             "$_[1] }\n";
542             }
543             # call method in lexical $var
544             return
545 0           "$_[1] sub { \n" .
546             #"$_[1] print 'params: ',Dumper(\@_);\n" .
547             "$_[1] my \$r = get_variable( '$cmd' );\n" .
548             "$_[1] \$_[3] = \$r->match( \$_[0], \$_[4], \$_[7], \$_[1] );\n" .
549             "$_[1] }\n";
550             }
551 0 0         if ( $prefix eq q(') ) { # single quoted literal '
552 0           $cmd = substr( $cmd, 1, -1 );
553 0 0         return "$_[1] constant( q!$cmd! )\n" unless $cmd =~ /!/;
554 0           return "$_[1] constant( q($cmd) )\n";
555             }
556 0 0         if ( $prefix eq q(") ) { # interpolated literal "
557 0           $cmd = substr( $cmd, 1, -1 );
558 0           warn "<\"...\"> not implemented";
559 0           return;
560             }
561 0 0         if ( $prefix eq '.' ) { # non_capturing_subrule / code assertion
562 0           $cmd = substr( $cmd, 1 );
563 0 0         if ( $cmd =~ /^{/ ) {
564 0           warn "code assertion not implemented";
565 0           return;
566             }
567 0           return call_subrule_no_capture( $cmd, $_[1], '' );
568             }
569 0 0         if ( $prefix eq '?' ) { # non_capturing_subrule / code assertion
570             # XXX FIXME
571 0           $cmd = substr( $cmd, 1 );
572 0 0         if ( $cmd =~ /^{/ ) {
573 0           warn "code assertion not implemented";
574 0           return;
575             }
576 0           return call_subrule_no_capture( $cmd, $_[1], '' );
577             }
578 0 0         if ( $prefix =~ /[_[:alnum:]]/ ) {
579 0 0         if ( $cmd eq 'cut' ) {
580 0           warn "<$cmd> not implemented";
581 0           return;
582             }
583 0 0         if ( $cmd eq 'commit' ) {
584 0           warn "<$cmd> not implemented";
585 0           return;
586             }
587             # capturing subrule
588             #
589 0           my ( $name, $param_list ) = split( /[\(\)]/, $cmd );
590 0 0         $param_list = '' unless defined $param_list;
591 0           my @param = split( ',', $param_list );
592 0           $capture_seen{$name}++;
593             #print "subrule ", $capture_seen{$name}, "\n";
594             #print "param: ", Dumper(\@param);
595             return
596 0   0       "$_[1] named( '$name', " .
597             ( $capture_to_array || ( $capture_seen{$name} > 1 ? 1 : 0 ) ) .
598             ", \n" .
599             call_subrule( $name, $_[1]." ", "", @param ) .
600             "$_[1] )\n";
601             }
602             #if ( $prefix eq '.' ) {
603             # my ( $method, $param_list ) = split( /[\(\)]/, $cmd );
604             # $method =~ s/^\.//;
605             # $param_list ||= '';
606             # return "$_[1] try_method( '$method', '$param_list' ) ";
607             #}
608 0           die "<$cmd> not implemented";
609             }
610              
611             1;