File Coverage

blib/lib/PDLA/NiceSlice.pm
Criterion Covered Total %
statement 151 197 76.6
branch 67 120 55.8
condition 27 63 42.8
subroutine 17 20 85.0
pod 1 14 7.1
total 263 414 63.5


line stmt bran cond sub pod time code
1             BEGIN {
2 77     77   595 my %engine_ok = (
3             'Filter::Util::Call' => 'PDLA/NiceSlice/FilterUtilCall.pm',
4             'Filter::Simple' => 'PDLA/NiceSlice/FilterSimple.pm',
5             'Module::Compile' => 'PDLA/NiceSlice/ModuleCompile.pm',
6             ); # to validate names
7              
8             ## $PDLA::NiceSlice::engine = $engine_ok{'Filter::Simple'}; # default engine type
9             ## TODO: Add configuration argument to perldl.conf
10 77         241 $PDLA::NiceSlice::engine = $engine_ok{'Filter::Util::Call'}; # default engine type
11              
12 77 50       2254 if ( exists $ENV{PDLA_NICESLICE_ENGINE} ) {
13 0         0 my $engine = $ENV{PDLA_NICESLICE_ENGINE};
14 0 0 0     0 if ( exists $engine_ok{$engine} and $engine_ok{$engine} ) {
    0 0        
15 0         0 $PDLA::NiceSlice::engine = $engine_ok{$engine};
16 0 0       0 warn "PDLA::NiceSlice using engine '$engine'\n" if $PDLA::verbose;
17             } elsif ( exists $engine_ok{$engine} and not $engine_ok{$engine} ) {
18 0 0       0 warn "PDLA::NiceSlice using default engine\n" if $PDLA::verbose;
19             } else {
20 0         0 die "PDLA::NiceSlice: PDLA_NICESLICE_ENGINE set to invalid engine '$engine'\n";
21             }
22             }
23             }
24              
25 77     77   429 no warnings;
  77         159  
  77         8909  
26              
27             package PDLA::NiceSlice;
28              
29             our $VERSION = '1.001';
30             $VERSION = eval $VERSION;
31              
32             $PDLA::NiceSlice::debug = defined($PDLA::NiceSlice::debug) ? $PDLA::NiceSlice::debug : 0;
33             # replace all occurences of the form
34             #
35             # $pdl(args);
36             # or
37             # $pdl->(args);
38             # with
39             #
40             # $pdl->slice(processed_args);
41             #
42             #
43             # Modified 2-Oct-2001: don't modify $var(LIST) if it's part of a
44             # "for $var(LIST)" or "foreach $var(LIST)" statement. CED.
45             #
46             # Modified 5-Nov-2007: stop processing if we encounter m/^no\s+PDLA\;:\;:NiceSlice\;\s*$/.
47              
48             # the next one is largely stolen from Regexp::Common
49             my $RE_cmt = qr'(?:(?:\#)(?:[^\n]*)(?:\n))';
50              
51             require PDLA::Version; # get PDLA version number
52             #
53             # remove code for PDLA versions earlier than 2.3
54             #
55              
56 77     77   53070 use Text::Balanced; # used to find parenthesis-delimited blocks
  77         1261884  
  77         4899  
57              
58             # Try overriding the current extract_quotelike() routine
59             # needed before using Filter::Simple to work around a bug
60             # between Text::Balanced and Filter::Simple for our purpose.
61             #
62              
63 0         0 BEGIN {
64              
65 77     77   677 no warnings; # quiet warnings for this
  77     0   174  
  77         211987  
66              
67             sub Text::Balanced::extract_quotelike (;$$)
68             {
69 0 0   0 1 0 my $textref = $_[0] ? \$_[0] : \$_;
70 0         0 my $wantarray = wantarray;
71 0 0       0 my $pre = defined $_[1] ? $_[1] : '\s*';
72            
73 0         0 my @match = Text::Balanced::_match_quotelike($textref,$pre,0,0); # do not match // alone as m//
74 0 0       0 return Text::Balanced::_fail($wantarray, $textref) unless @match;
75 0         0 return Text::Balanced::_succeed($wantarray, $textref,
76             $match[2], $match[18]-$match[2], # MATCH
77             @match[18,19], # REMAINDER
78             @match[0,1], # PREFIX
79             @match[2..17], # THE BITS
80             @match[20,21], # ANY FILLET?
81             );
82             };
83              
84             };
85              
86              
87             # a call stack for error processing
88             my @callstack = ('stackbottom');
89             sub curarg {
90 2     2 0 5 my $arg = $callstack[-1]; # return top element of stack
91 2         12 $arg =~ s/\((.*)\)/$1/s;
92 2         25 return $arg;
93             }
94 2875     2875 0 6105 sub savearg ($) {push @callstack,$_[0]}
95 660     660 0 1109 sub poparg () {pop @callstack}
96              
97             my @srcstr = (); # stack for refs to current source strings
98             my $offset = 1; # line offset
99             my $file = 'unknown';
100              
101             my $mypostfix = '';
102              
103             sub autosever {
104 0     0 0 0 my ($this,$arg) = @_;
105 0 0       0 $arg = 1 unless defined $arg;
106 0 0       0 if ($arg) {$mypostfix = '->sever'} else
  0         0  
107 0         0 {$mypostfix = ''}
108             }
109              
110             sub line {
111 2 50   2 0 6 die __PACKAGE__." internal error: can't determine line number"
112             if $#srcstr < 0;
113 2         4 my $pretext = substr ${$srcstr[0]}, 0, pos(${$srcstr[0]})-1;
  2         4  
  2         7  
114 2         12 return ($pretext =~ tr/\n/\n/)+$offset;
115             }
116              
117             sub filterdie {
118 2     2 0 6 my ($msg) = @_;
119 2         11 die "$msg\n\t at $file near line ".
120             line().", slice expression '".curarg()."'\n";
121             }
122              
123             # non-bracketed prefix matching regexp
124             my $prebrackreg = qr/^([^\(\{\[]*)/;
125              
126             # split regex $re separated arglist
127             # but ignore bracket-protected bits
128             # (i.e. text that is within matched brackets)
129             sub splitprotected ($$) {
130 7292     7292 0 14555 my ($re,$txt) = @_;
131 7292         12143 my ($got,$pre) = (1,'');
132 7292         12293 my @chunks = ('');
133 7292         9665 my $ct = 0; # infinite loop protection
134 7292   66     32939 while ($got && $txt =~ /[({\[]/ && $ct++ < 1000) {
      66        
135             # print "iteration $ct\n";
136 3869         9620 ($got,$txt,$pre) =
137             Text::Balanced::extract_bracketed($txt,'{}()[]',$prebrackreg);
138 3869         547595 my @partialargs = split $re, $pre, -1;
139 3869 100       11963 $chunks[-1] .= shift @partialargs if @partialargs;
140 3869         6428 push @chunks, @partialargs;
141 3869         19588 $chunks[-1] .= $got;
142             }
143 7292 50       13992 filterdie "possible infinite parse loop, slice arg '".curarg()."'"
144             if $ct == 1000;
145 7292         57819 my @partialargs = split $re, $txt, -1;
146 7292 100       21259 $chunks[-1] .= shift @partialargs if @partialargs;
147 7292         12389 push @chunks, @partialargs;
148 7292         19840 return @chunks;
149             }
150              
151             # a pattern that finds occurences of the form
152             #
153             # $var(
154             #
155             # and
156             #
157             # ->(
158             #
159             # used as the prefix pattern for findslice
160             my $prefixpat = qr/.*? # arbitrary leading stuff
161             ((?
162             |->) # or just '->'
163             (\s|$RE_cmt)* # ignore comments
164             \s* # more whitespace
165             (?=\()/smx; # directly followed by open '(' (look ahead)
166              
167             # translates a single arg into corresponding slice format
168             sub onearg ($) {
169 4415     4415 0 8487 my ($arg) = @_;
170 4415 50       8308 print STDERR "processing arg '$arg'\n" if $PDLA::NiceSlice::debug;
171 4415 100       15046 return q|'X'| if $arg =~ /^\s*:??\s*$/; # empty arg or just colon
172             # recursively process args for slice syntax
173 4260 100       23523 $arg = findslice($arg,$PDLA::debug) if $arg =~ $prefixpat;
174             # no doubles colon are matched to avoid confusion with Perl's C<::>
175 4260 100       10910 if ($arg =~ /(?
176 1544         2992 my @args = splitprotected '(?
177 1544 50       3423 filterdie "invalid range in slice expression '".curarg()."'"
178             if @args > 3;
179 1544 50 33     7042 $args[0] = 0 if !defined $args[0] || $args[0] =~ /^\s*$/;
180 1544 50 33     5807 $args[1] = -1 if !defined $args[1] || $args[1] =~ /^\s*$/;
181 1544 100 66     4154 $args[2] = undef if !defined $args[2] || $args[2] =~ /^\s*$/;
182 1544         7407 return "[".join(',',@args)."]"; # replace single ':' with ','
183             }
184             # the (pos) syntax, i.e. 0D slice
185 2716 100       15685 return "[$arg,0,0]" if $arg =~ s/^\s*\((.*)\)\s*$/$1/; # use the new [x,x,0]
186             # we don't allow [] syntax (although that's what slice uses)
187 787 50       1881 filterdie "invalid slice expression containing '[', expression was '".
188             curarg()."'" if $arg =~ /^\s*\[/;
189              
190             # If the arg starts with '*' it's a dummy call -- force stringification
191             # and prepend a '*' for handling by slice.
192 787 100       2479 return "(q(*).($arg))" if($arg =~ s/^\s*\*//);
193              
194             # this must be a simple position, leave as is
195 633         2195 return "$arg";
196             }
197              
198             # process the arg list
199             sub procargs {
200 2873     2873 0 5029 my ($txt) = @_;
201 2873 50       5167 print STDERR "procargs: got '$txt'\n" if $PDLA::NiceSlice::debug;
202             # $txt =~ s/^\s*\((.*)\)\s*$/$1/s; # this is now done by findslice
203             # push @callstack, $txt; # for later error reporting
204             my $args = $txt =~ /^\s*$/s ? '' :
205 2873 50       14785 join ',', map {onearg $_} splitprotected ',', $txt;
  4415         11069  
206             ## Leave whitespace/newlines in so line count
207             ## is preserved in error messages. Makes the
208             ## filtered output ugly---iffi the input was
209             ## ugly...
210             ##
211             ## $args =~ s/\s//sg; # get rid of whitespace
212             # pop @callstack; # remove from call stack
213 2873 50       7309 print STDERR "procargs: returned '($args)'\n" if $PDLA::NiceSlice::debug;
214 2873         6995 return "($args)";
215             }
216              
217             # this is the real workhorse that translates occurences
218             # of $x(args) into $args->slice(processed_arglist)
219             #
220             sub findslice {
221 662     662 0 6385 my ($src,$verb) = @_;
222 662         1443 push @srcstr, \$src;
223 662 100       1744 $verb = 0 unless defined $verb;
224 662         1137 my $processed = '';
225 662         966 my $ct=0; # protect against infinite loop
226 662         1031 my ($found,$prefix,$dummy);
227 662   66     72178 while ( $src =~ m/\G($prefixpat)/ && (($found,$dummy,$prefix) =
      66        
228             Text::Balanced::extract_bracketed($src,'()',$prefixpat))[0]
229             && $ct++ < 1000) {
230 3345 50       861604 print STDERR "pass $ct: found slice expr $found at line ".line()."\n"
231             if $verb;
232              
233             # Do final check for "for $var(LIST)" and "foreach $var(LIST)" syntax.
234             # Process into an 'slice' call only if it's not that.
235              
236 3345 100 100     38178 if ($prefix =~ m/for(each)?(\s+(my|our))?\s+\$\w+(\s|$RE_cmt)*$/s ||
237             # foreach statement: Don't translate
238             $prefix =~ m/->\s*\$\w+$/s) # e.g. $x->$method(args)
239             # method invocation via string, don't translate either
240             {
241             # note: even though we reject this one we need to call
242             # findslice on $found in case
243             # it contains slice expressions
244 470         2118 $processed .= "$prefix".findslice($found);
245             } else { # statement is a real slice and not a foreach
246              
247 2875         5521 my ($call,$pre,$post,$arg);
248              
249             # the following section got an overhaul in v0.99
250             # to fix modifier parsing and allow >1 modifier
251             # this code still needs polishing
252 2875         7263 savearg $found; # error reporting
253 2875 50       5547 print STDERR "findslice: found '$found'\n" if $PDLA::NiceSlice::debug;
254 2875         14549 $found =~ s/^\s*\((.*)\)\s*$/$1/s;
255 2875         7039 my ($slicearg,@mods) = splitprotected ';', $found;
256 2875 50       6357 filterdie "more than 1 modifier group: @mods" if @mods > 1;
257             # filterdie "invalid modifier $1"
258             # if $found =~ /(;\s*[[:graph:]]{2,}?\s*)\)$/;
259 2875 50       5340 print STDERR "MODS: " . join(',',@mods) . "\n" if $PDLA::NiceSlice::debug;
260 2875         4033 my @post = (); # collects all post slice operations
261 2875         3907 my @pre = ();
262 2875 100       5589 if (@mods) {
263 7         29 (my $mod = $mods[0]) =~ s/\s//sg; # eliminate whitespace
264 7         20 my @modflags = split '', $mod;
265 7 50       16 print STDERR "MODFLAGS: @modflags\n" if $PDLA::NiceSlice::debug;
266 7 100 100     45 filterdie "more than 1 modifier incompatible with ?: @modflags"
267             if @modflags > 1 && grep (/\?/, @modflags); # only one flag with where
268 6         13 my %seen = ();
269 6 100       14 if (@modflags) {
270 5         11 for my $mod1 (@modflags) {
271 9 100       35 if ($mod1 eq '?') {
    100          
    100          
    50          
272 1 50       5 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
273 1         3 $call = 'where';
274 1         3 $arg = "(" . findslice($slicearg) . ")";
275             # $post = ''; # no post action required
276             } elsif ($mod1 eq '_') {
277 1 50       5 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
278 1         3 push @pre, 'flat->';
279 1   50     6 $call ||= 'slice'; # do only once
280 1         3 $arg = procargs($slicearg);
281             # $post = ''; # no post action required
282             } elsif ($mod1 eq '|') {
283 4 100       15 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
284 3   50     8 $call ||= 'slice';
285 3   33     6 $arg ||= procargs($slicearg);
286 3         10 push @post, '->sever';
287             } elsif ($mod1 eq '-') {
288 3 50       13 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
289 3   50     14 $call ||= 'slice';
290 3   33     15 $arg ||= procargs($slicearg);
291 3         8 push @post, '->reshape(-1)';
292             } else {
293 0         0 filterdie "unknown modifier $mod1";
294             }
295             }
296             } else { # empty modifier block
297 1         2 $call = 'slice';
298 1         3 $arg = procargs($slicearg);
299             # $post = '';
300             }
301             } else { # no modifier block
302 2868         4408 $call = 'slice';
303 2868         5471 $arg = procargs($slicearg);
304             # $post = '';
305             # $call = 'slice_if_pdl'; # handle runtime checks for $self type
306             # $arg =~ s/\)$/,q{$found})/; # add original argument string
307             # in case $self is not a piddle
308             # and the original call must be
309             # generated
310             }
311 2873         5429 $pre = join '', @pre;
312             # assumption here: sever should be last
313             # and order of other modifiers doesn't matter
314 2873         5477 $post = join '', sort @post; # need to ensure that sever is last
315 2873 100       294254 $processed .= "$prefix". ($prefix =~ /->(\s*$RE_cmt*)*$/ ?
316             '' : '->').
317             $pre.$call.$arg.$post.$mypostfix;
318             }
319              
320             } # end of while loop
321              
322 660         1954 poparg; # clean stack
323 660         1038 pop @srcstr; # clear stack
324             # append the remaining text portion
325             # use substr only if we have had at least one pass
326             # through above loop (otherwise pos is uninitialized)
327 660 100       15906 $processed .= $ct > 0 ? substr $src, pos($src) : $src;
328             }
329              
330             ##############################
331             # termstr - generate a regexp to find turn-me-off strings
332             # CED 5-Nov-2007
333             sub terminator_regexp{
334 81     81 0 232 my $clstr = shift;
335 81         920 $clstr =~ s/([^a-zA-Z0-9])/\\$1/g;
336 81         337 my $termstr = '^\s*no\s+'.$clstr.'\s*;\s*(#.*)*$';
337 81         1834 return qr/$termstr/o; # allow trailing comments
338             }
339              
340             sub reinstator_regexp{
341 1     1 0 3 my $clstr = shift;
342 1         10 $clstr =~ s/([^a-zA-Z0-9])/\\$1/g;
343 1         5 my $reinstr = '^\s*use\s+'.$clstr.'\s*;\s*(#.*)*$';
344 1         30 return qr/$reinstr/o; # allow trailing comments
345             }
346              
347             # save eval of findslice that should be used within perldla or pdla2
348             # as a preprocessor
349             sub perldlpp {
350 1     1 0 6 my ($class, $txt) = @_;
351 1         2 local($_);
352             ##############################
353             # Backwards compatibility to before the two-parameter form. The only
354             # call should be around line 206 of PDLA::AutoLoader, but one never
355             # knows....
356             # -- CED 5-Nov-2007
357 1 50       3 if(!defined($txt)) {
358 0         0 print "PDLA::NiceSlice::perldlpp -- got deprecated one-argument form, from ".(join("; ",caller))."...\n";
359 0         0 $txt = $class;
360 0         0 $class = "PDLA::NiceSlice";
361             }
362              
363             ## Debugging to track exactly what is going on -- left in, in case it's needed again
364 1 50       4 if($PDLA::debug > 1) {
365 0         0 print "PDLA::NiceSlice::perldlpp - got:\n$txt\n";
366 0         0 my $i;
367 0         0 for $i(0..5){
368 0         0 my($package,$filename,$line,$subroutine, $hasargs) = caller($i);
369 0         0 printf("layer %d: %20s, %40s, line %5d, sub %20s, args: %d\n",$i,$package,$filename,$line,$subroutine,$hasargs);
370             }
371             }
372              
373 1         2 my $new;
374              
375             ##############################
376             ## This block sort-of echoes import(), below...
377             ## Crucial difference: we don't give up the ghost on termination conditions, only
378             ## mask out current findslices. That's because future uses won't be processed
379             ## (for some reason source filters don't work on evals).
380              
381 1         8 my @lines= split /\n/,$txt;
382              
383 1         7 my $terminator = terminator_regexp($class);
384 1         5 my $reinstator = reinstator_regexp($class);
385              
386 1         3 my($status, $off, $end);
387 1         2 eval {
388 1   33     2 do {
389 1         2 my $data = "";
390 1         4 while(@lines) {
391 12         19 $_= shift @lines;
392 12 50 33     55 if(defined($terminator) && m/$terminator/) {
393 0         0 $_ = "## $_";
394 0         0 $off = 1;
395 0         0 last;
396             }
397 12 50 33     44 if(defined($reinstator) && m/$reinstator/) {
398 0         0 $_ = "## $_";
399             }
400 12 50       26 if(m/^\s*(__END__|__DATA__)\s*$/) {
401 0         0 $end=$1; $off = 1;
  0         0  
402 0         0 last;
403             }
404 12         23 $data .= "$_\n";
405 12         13 $count++;
406 12         22 $_="";
407             }
408 1         5 $_ = $data;
409 1         3 $_ = findslice $_ ;
410 1 50       4 $_ .= "no $class;\n" if $off;
411 1 50       3 $_ .= "$end\n" if $end;
412 1         4 $new .= "$_";
413            
414 1   33     7 while($off && @lines) {
415 0         0 $_ = shift @lines;
416 0 0 0     0 if(defined($reinstator) && m/$reinstator/) {
417 0         0 $off = 0;
418 0         0 $_ = "## $_";
419             }
420 0 0 0     0 if(defined($terminator) && m/$terminator/) {
421 0         0 $_ = "## $_";
422             }
423              
424 0         0 $new .= "$_\n";
425              
426             }
427             } while(@lines && !$end);
428             };
429            
430 1 50       4 if ($@) {
431 0         0 my $err = $@;
432 0         0 for (split '','#!|\'"%~/') {
433 0 0       0 return "print q${_}NiceSlice error: $err${_}"
434             unless $err =~ m{[$_]};
435             }
436 0         0 return "print q{NiceSlice error: $err}"; # if this doesn't work
437             # we're stuffed
438             }
439              
440 1 50       4 if($PDLA::debug > 1) {
441 0         0 print "PDLA::NiceSlice::perldlpp - returning:\n$new\n";
442             }
443 1         6 return $new;
444             }
445              
446             BEGIN {
447 77     77   37500 require "$PDLA::NiceSlice::engine";
448             }
449              
450             =head1 NAME
451              
452             PDLA::NiceSlice - toward a nicer slicing syntax for PDLA
453              
454             =head1 SYNOPSYS
455              
456             use PDLA::NiceSlice;
457              
458             $x(1:4) .= 2; # concise syntax for ranges
459             print $y((0),1:$end); # use variables in the slice expression
460             $x->xchg(0,1)->(($pos-1)) .= 0; # default method syntax
461              
462             $idx = long 1, 7, 3, 0; # a piddle of indices
463             $x(-3:2:2,$idx) += 3; # mix explicit indexing and ranges
464             $x->clump(1,2)->(0:30); # 'default method' syntax
465             $x(myfunc(0,$var),1:4)++; # when using functions in slice expressions
466             # use parentheses around args!
467              
468             $y = $x(*3); # Add dummy dimension of order 3
469              
470             # modifiers are specified in a ;-separated trailing block
471             $x($x!=3;?)++; # short for $x->where($x!=3)++
472             $x(0:1114;_) .= 0; # short for $x->flat->(0:1114)
473             $y = $x(0:-1:3;|); # short for $x(0:-1:3)->sever
474             $n = sequence 3,1,4,1;
475             $y = $n(;-); # drop all dimensions of size 1 (AKA squeeze)
476             $y = $n(0,0;-|); # squeeze *and* sever
477             $c = $x(0,3,0;-); # more compact way of saying $x((0),(3),(0))
478              
479             =head1 DESCRIPTION
480              
481             Slicing is a basic, extremely common operation, and PDLA's
482             L method would be cumbersome to use in many
483             cases. C rectifies that by incorporating new slicing
484             syntax directly into the language via a perl I (see
485             L). NiceSlice adds no new functionality, only convenient syntax.
486              
487             NiceSlice is loaded automatically in the perldla or pdla2 shell, but (to avoid
488             conflicts with other modules) must be loaded explicitly in standalone
489             perl/PDLA scripts (see below). If you prefer not to use a prefilter on
490             your standalone scripts, you can use the L
491             method in those scripts,
492             rather than the more compact NiceSlice constructs.
493              
494             =head1 Use in scripts and C or C shell
495              
496             The new slicing syntax can be switched on and off in scripts
497             and perl modules by using or unloading C.
498              
499             But now back to scripts and modules.
500             Everything after C will be translated
501             and you can use the new slicing syntax. Source filtering
502             will continue until the end of the file is encountered.
503             You can stop sourcefiltering before the end of the file
504             by issuing a C statement.
505              
506             Here is an example:
507              
508             use PDLA::NiceSlice;
509              
510             # this code will be translated
511             # and you can use the new slicing syntax
512              
513             no PDLA::NiceSlice;
514              
515             # this code won't
516             # and the new slicing syntax will raise errors!
517              
518             See also L and F in this distribution for
519             further examples.
520              
521             NOTE: Unlike "normal" modules you need to include a
522             C call in each and every file that
523             contains code that uses the new slicing syntax. Imagine
524             the following situation: a file F
525              
526             # start test0.pl
527             use PDLA;
528             use PDLA::NiceSlice;
529              
530             $x = sequence 10;
531             print $x(0:4),"\n";
532              
533             require 'test1.pl';
534             # end test0.pl
535              
536             that Cs a second file F
537              
538             # begin test1.pl
539             $aa = sequence 11;
540             print $aa(0:7),"\n";
541             1;
542             # end test1.pl
543              
544             Following conventional perl wisdom everything should be alright
545             since we Cd C and C already from within
546             F and by the time F is Cd things should
547             be defined and imported, etc. A quick test run will, however, produce
548             something like the following:
549              
550             perl test0.pl
551             [0 1 2 3 4]
552             syntax error at test1.pl line 3, near "0:"
553             Compilation failed in require at test0.pl line 7.
554              
555             This can be fixed by adding the line
556              
557             use PDLA::NiceSlice;
558              
559             C the code in F that uses the
560             new slicing syntax (to play safe just include the line
561             near the top of the file), e.g.
562              
563             # begin corrected test1.pl
564             use PDLA::NiceSlice;
565             $aa = sequence 11;
566             print $aa(0:7),"\n";
567             1;
568             # end test1.pl
569              
570             Now things proceed more smoothly
571              
572             perl test0.pl
573             [0 1 2 3 4]
574             [0 1 2 3 4 5 6 7]
575              
576             Note that we don't need to issue C again.
577             C is a somewhat I module in
578             that respect. It is a consequence of the way source
579             filtering works in Perl (see also the IMPLEMENTATION
580             section below).
581              
582             =head2 evals and C
583              
584             Due to C being a source filter it won't work
585             in the usual way within evals. The following will I do what
586             you want:
587              
588             $x = sequence 10;
589             eval << 'EOE';
590              
591             use PDLA::NiceSlice;
592             $y = $x(0:5);
593              
594             EOE
595             print $y;
596              
597             Instead say:
598              
599             use PDLA::NiceSlice;
600             $x = sequence 10;
601             eval << 'EOE';
602              
603             $y = $x(0:5);
604              
605             EOE
606             print $y;
607              
608             Source filters I be executed at compile time to be effective. And
609             C is just a source filter (although it is not
610             necessarily obvious for the casual user).
611              
612             =head1 The new slicing syntax
613              
614             Using C slicing piddles becomes so much easier since, first of
615             all, you don't need to make explicit method calls. No
616              
617             $pdl->slice(....);
618              
619             calls, etc. Instead, C introduces two ways in which to
620             slice piddles without too much typing:
621              
622             =over 2
623              
624             =item *
625              
626             using parentheses directly following a scalar variable name,
627             for example
628              
629             $c = $y(0:-3:4,(0));
630              
631             =item *
632              
633             using the so called I invocation in which the
634             piddle object is treated as if it were a reference to a
635             subroutine (see also L). Take this example that slices
636             a piddle that is part of a perl list C<@b>:
637              
638             $c = $b[0]->(0:-3:4,(0));
639              
640             =back
641              
642             The format of the argument list is the same for both types of
643             invocation and will be explained in more detail below.
644              
645             =head2 Parentheses following a scalar variable name
646              
647             An arglist in parentheses following directly after a scalar variable
648             name that is I preceded by C<&> will be resolved as a slicing
649             command, e.g.
650              
651             $x(1:4) .= 2; # only use this syntax on piddles
652             $sum += $x(,(1));
653              
654             However, if the variable name is immediately preceded by a C<&>,
655             for example
656              
657             &$x(4,5);
658              
659             it will not be interpreted as a slicing expression. Rather, to avoid
660             interfering with the current subref syntax, it will be treated as an
661             invocation of the code reference C<$x> with argumentlist C<(4,5)>.
662              
663             The $x(ARGS) syntax collides in a minor way with the perl syntax. In
664             particular, ``foreach $var(LIST)'' appears like a PDLA slicing call.
665             NiceSlice avoids translating the ``for $var(LIST)'' and
666             ``foreach $var(LIST)'' constructs for this reason. Since you
667             can't use just any old lvalue expression in the 'foreach' 'for'
668             constructs -- only a real perl scalar will do -- there's no
669             functionality lost. If later versions of perl accept
670             ``foreach (LIST)'', then you can use the code ref
671             syntax, below, to get what you want.
672              
673             =head2 The I syntax
674              
675             The second syntax that will be recognized is what I called the
676             I syntax. It is the method arrow C<-E> directly
677             followed by an open parenthesis, e.g.
678              
679             $x->xchg(0,1)->(($pos)) .= 0;
680              
681             Note that this conflicts with the use of normal code references, since you
682             can write in plain Perl
683              
684             $sub = sub { print join ',', @_ };
685             $sub->(1,'a');
686              
687             NOTE: Once C is in effect (you can always switch it off with
688             a line C anywhere in the script) the source filter will incorrectly
689             replace the above call to C<$sub> with an invocation of the slicing method.
690             This is one of the pitfalls of using a source filter that doesn't know
691             anything about the runtime type of a variable (cf. the
692             Implementation section).
693              
694             This shouldn't be a major problem in practice; a simple workaround is to use
695             the C<&>-way of calling subrefs, e.g.:
696              
697             $sub = sub { print join ',', @_ };
698             &$sub(1,'a');
699              
700             =head2 When to use which syntax?
701              
702             Why are there two different ways to invoke slicing?
703             The first syntax C<$x(args)> doesn't work with chained method calls. E.g.
704              
705             $x->xchg(0,1)(0);
706              
707             won't work. It can I be used directly following a valid perl variable
708             name. Instead, use the I syntax in such cases:
709              
710             $x->xchg(0,1)->(0);
711              
712             Similarly, if you have a list of piddles C<@pdls>:
713              
714             $y = $pdls[5]->(0:-1);
715              
716             =head2 The argument list
717              
718             The argument list is a comma separated list. Each argument specifies
719             how the corresponding dimension in the piddle is sliced. In contrast
720             to usage of the L method the arguments should
721             I be quoted. Rather freely mix literals (1,3,etc), perl
722             variables and function invocations, e.g.
723              
724             $x($pos-1:$end,myfunc(1,3)) .= 5;
725              
726             There can even be other slicing commands in the arglist:
727              
728             $x(0:-1:$pdl($step)) *= 2;
729              
730             NOTE: If you use function calls in the arglist make sure that
731             you use parentheses around their argument lists. Otherwise the
732             source filter will get confused since it splits the argument
733             list on commas that are not protected by parentheses. Take
734             the following example:
735              
736             sub myfunc { return 5*$_[0]+$_[1] }
737             $x = sequence 10;
738             $sl = $x(0:myfunc 1, 2);
739             print $sl;
740             PDLA barfed: Error in slice:Too many dims in slice
741             Caught at file /usr/local/bin/perldla, line 232, pkg main
742              
743              
744             The simple fix is
745              
746             $sl = $x(0:myfunc(1, 2));
747             print $sl;
748             [0 1 2 3 4 5 6 7]
749              
750             Note that using prototypes in the definition of myfunc does not help.
751             At this stage the source filter is simply not intelligent enough to
752             make use of this information. So beware of this subtlety.
753              
754             Another pitfall to be aware of: currently, you can't use the conditional
755             operator in slice expressions (i.e., C, since the parser confuses them
756             with ranges). For example, the following will cause an error:
757              
758             $x = sequence 10;
759             $y = rand > 0.5 ? 0 : 1; # this one is ok
760             print $x($y ? 1 : 2); # error !
761             syntax error at (eval 59) line 3, near "1,
762              
763             For the moment, just try to stay clear of the conditional operator
764             in slice expressions (or provide us with a patch to the parser to
765             resolve this issue ;).
766              
767             =head2 Modifiers
768              
769             Following a suggestion originally put forward by Karl Glazebrook the
770             latest versions of C implement I in slice
771             expressions. Modifiers are convenient shorthands for common variations
772             on PDLA slicing. The general syntax is
773              
774             $pdl(;)
775              
776             Four modifiers are currently implemented:
777              
778             =over
779              
780             =item *
781              
782             C<_> : I the piddle before applying the slice expression. Here
783             is an example
784              
785             $y = sequence 3, 3;
786             print $y(0:-2;_); # same as $y->flat->(0:-2)
787             [0 1 2 3 4 5 6 7]
788              
789             which is quite different from the same slice expression without the modifier
790              
791             print $y(0:-2);
792             [
793             [0 1]
794             [3 4]
795             [6 7]
796             ]
797              
798             =item *
799              
800             C<|> : L the link to the piddle, e.g.
801              
802             $x = sequence 10;
803             $y = $x(0:2;|)++; # same as $x(0:2)->sever++
804             print $y;
805             [1 2 3]
806             print $x; # check if $x has been modified
807             [0 1 2 3 4 5 6 7 8 9]
808              
809             =item *
810              
811             C : short hand to indicate that this is really a
812             L expression
813              
814             As expressions like
815              
816             $x->where($x>5)
817              
818             are used very often you can write that shorter as
819              
820             $x($x>5;?)
821              
822             With the C-modifier the expression preceding the modifier is I
823             really a slice expression (e.g. ranges are not allowed) but rather an
824             expression as required by the L method.
825             For example, the following code will raise an error:
826              
827             $x = sequence 10;
828             print $x(0:3;?);
829             syntax error at (eval 70) line 3, near "0:"
830              
831             That's about all there is to know about this one.
832              
833             =item *
834              
835             C<-> : I out any singleton dimensions. In less technical terms:
836             reduce the number of dimensions (potentially) by deleting all
837             dims of size 1. It is equivalent to doing a L(-1).
838             That can be very handy if you want to simplify
839             the results of slicing operations:
840              
841             $x = ones 3, 4, 5;
842             $y = $x(1,0;-); # easier to type than $x((1),(0))
843             print $y->info;
844             PDLA: Double D [5]
845              
846             It also provides a unique opportunity to have smileys in your code!
847             Yes, PDLA gives new meaning to smileys.
848              
849             =back
850              
851             =head2 Combining modifiers
852              
853             Several modifiers can be used in the same expression, e.g.
854              
855             $c = $x(0;-|); # squeeze and sever
856              
857             Other combinations are just as useful, e.g. C<;_|> to flatten and
858             sever. The sequence in which modifiers are specified is not important.
859              
860             A notable exception is the C modifier (C) which must not
861             be combined with other flags (let me know if you see a good reason
862             to relax this rule).
863              
864             Repeating any modifier will raise an error:
865              
866             $c = $x(-1:1;|-|); # will cause error
867             NiceSlice error: modifier | used twice or more
868              
869             Modifiers are still a new and experimental feature of
870             C. I am not sure how many of you are actively using
871             them. I. I think
872             modifiers are very useful and make life a lot easier. Feedback is
873             welcome as usual. The modifier syntax will likely be further tuned in
874             the future but we will attempt to ensure backwards compatibility
875             whenever possible.
876              
877             =head2 Argument formats
878              
879             In slice expressions you can use ranges and secondly,
880             piddles as 1D index lists (although compare the description
881             of the C-modifier above for an exception).
882              
883             =over 2
884              
885             =item * ranges
886              
887             You can access ranges using the usual C<:> separated format:
888              
889             $x($start:$stop:$step) *= 4;
890              
891             Note that you can omit the trailing step which then defaults to 1. Double
892             colons (C<::>) are not allowed to avoid clashes with Perl's namespace
893             syntax. So if you want to use steps different from the default
894             you have to also at least specify the stop position.
895             Examples:
896              
897             $x(::2); # this won't work (in the way you probably intended)
898             $x(:-1:2); # this will select every 2nd element in the 1st dim
899              
900             Just as with L negative indices count from the end of the dimension
901             backwards with C<-1> being the last element. If the start index is larger
902             than the stop index the resulting piddle will have the elements in reverse
903             order between these limits:
904              
905             print $x(-2:0:2);
906             [8 6 4 2 0]
907              
908             A single index just selects the given index in the slice
909              
910             print $x(5);
911             [5]
912              
913             Note, however, that the corresponding dimension is not removed from
914             the resulting piddle but rather reduced to size 1:
915              
916             print $x(5)->info
917             PDLA: Double D [1]
918              
919             If you want to get completely rid of that dimension enclose the index
920             in parentheses (again similar to the L syntax):
921              
922             print $x((5));
923             5
924              
925             In this particular example a 0D piddle results. Note that this syntax is
926             only allowed with a single index. All these will be errors:
927              
928             print $x((0,4)); # will work but not in the intended way
929             print $x((0:4)); # compile time error
930              
931             An empty argument selects the whole dimension, in this example
932             all of the first dimension:
933              
934             print $x(,(0));
935              
936             Alternative ways to select a whole dimension are
937              
938             $x = sequence 5, 5;
939             print $x(:,(0));
940             print $x(0:-1,(0));
941             print $x(:-1,(0));
942             print $x(0:,(0));
943              
944             Arguments for trailing dimensions can be omitted. In that case
945             these dimensions will be fully kept in the sliced piddle:
946              
947             $x = random 3,4,5;
948             print $x->info;
949             PDLA: Double D [3,4,5]
950             print $x((0))->info;
951             PDLA: Double D [4,5]
952             print $x((0),:,:)->info; # a more explicit way
953             PDLA: Double D [4,5]
954             print $x((0),,)->info; # similar
955             PDLA: Double D [4,5]
956              
957             =item * dummy dimensions
958              
959             As in L, you can insert a dummy dimension by preceding a
960             single index argument with '*'. A lone '*' inserts a dummy dimension of
961             order 1; a '*' followed by a number inserts a dummy dimension of that order.
962              
963             =item * piddle index lists
964              
965             The second way to select indices from a dimension is via 1D piddles
966             of indices. A simple example:
967              
968             $x = random 10;
969             $idx = long 3,4,7,0;
970             $y = $x($idx);
971              
972             This way of selecting indices was previously only possible using
973             L (C attempts to unify the
974             C and C interfaces). Note that the indexing piddles must
975             be 1D or 0D. Higher dimensional piddles as indices will raise an error:
976              
977             $x = sequence 5, 5;
978             $idx2 = ones 2,2;
979             $sum = $x($idx2)->sum;
980             piddle must be <= 1D at /home/XXXX/.perldlrc line 93
981              
982             Note that using index piddles is not as efficient as using ranges.
983             If you can represent the indices you want to select using a range
984             use that rather than an equivalent index piddle. In particular,
985             memory requirements are increased with index piddles (and execution
986             time I be longer). That said, if an index piddle is the way to
987             go use it!
988              
989             =back
990              
991             As you might have expected ranges and index piddles can be freely
992             mixed in slicing expressions:
993              
994             $x = random 5, 5;
995             $y = $x(-1:2,pdl(3,0,1));
996              
997             =head2 piddles as indices in ranges
998              
999             You can use piddles to specify indices in ranges. No need to
1000             turn them into proper perl scalars with the new slicing syntax.
1001             However, make sure they contain not more than one element! Otherwise
1002             a runtime error will be triggered. First a couple of examples that
1003             illustrate proper usage:
1004              
1005             $x = sequence 5, 5;
1006             $rg = pdl(1,-1,3);
1007             print $x($rg(0):$rg(1):$rg(2),2);
1008             [
1009             [11 14]
1010             ]
1011             print $x($rg+1,:$rg(0));
1012             [
1013             [2 0 4]
1014             [7 5 9]
1015             ]
1016              
1017             The next one raises an error
1018              
1019             print $x($rg+1,:$rg(0:1));
1020             multielement piddle where only one allowed at XXX/Core.pm line 1170.
1021              
1022             The problem is caused by using the 2-element piddle C<$rg(0:1)> as the
1023             stop index in the second argument C<:$rg(0:1)> that is interpreted as
1024             a range by C. You I use multielement piddles as
1025             index piddles as described above but not in ranges. And
1026             C treats any expression with unprotected C<:>'s as a
1027             range. I means as usual
1028             I<"not occurring between matched parentheses">.
1029              
1030             =head1 IMPLEMENTATION
1031              
1032             C exploits the ability of Perl to use source filtering
1033             (see also L). A source filter basically filters (or
1034             rewrites) your perl code before it is seen by the
1035             compiler. C searches through your Perl source code and when
1036             it finds the new slicing syntax it rewrites the argument list
1037             appropriately and splices a call to the C method using the
1038             modified arg list into your perl code. You can see how this works in
1039             the L or L shells by switching on
1040             reporting (see above how to do that).
1041              
1042             =head1 BUGS
1043              
1044             =head2 Conditional operator
1045              
1046             The conditional operator can't be used in slice expressions (see
1047             above).
1048              
1049             =head2 The C file handle
1050              
1051             I: To avoid clobbering the C filehandle C
1052             switches itself off when encountering the C<__END__> or C<__DATA__> tokens.
1053             This should not be a problem for you unless you use C to load
1054             PDLA code including the new slicing from that section. It is even desirable
1055             when working with L, see below.
1056              
1057             =head2 Possible interaction with L
1058              
1059             There is currently an undesired interaction between C
1060             and the new L module (currently only in
1061             PDLA CVS). Since PP code generally
1062             contains expressions of the type C<$var()> (to access piddles, etc)
1063             C recognizes those I as
1064             slice expressions and does its substitutions. This is not a problem
1065             if you use the C section for your Pdlapp code -- the recommended
1066             place for Inline code anyway. In that case
1067             C will have switched itself off before encountering any
1068             Pdlapp code (see above):
1069              
1070             # use with Inline modules
1071             use PDLA;
1072             use PDLA::NiceSlice;
1073             use Inline Pdlapp;
1074              
1075             $x = sequence(10);
1076             print $x(0:5);
1077              
1078             __END__
1079              
1080             __Pdlapp__
1081              
1082             ... inline stuff
1083              
1084              
1085             Otherwise switch C explicitly off around the
1086             Inline::Pdlapp code:
1087              
1088             use PDLA::NiceSlice;
1089              
1090             $x = sequence 10;
1091             $x(0:3)++;
1092             $x->inc;
1093              
1094             no PDLA::NiceSlice; # switch off before Pdlapp code
1095             use Inline Pdlapp => "Pdlapp source code";
1096              
1097             The cleaner solution is to always stick with the
1098             C way of including your C code as
1099             in the first example. That way you keep your nice Perl
1100             code at the top and all the ugly Pdlapp stuff etc at
1101             the bottom.
1102              
1103             =head2 Bug reports
1104              
1105             Feedback and bug reports are welcome. Please include an example
1106             that demonstrates the problem. Log bug reports in the PDLA
1107             issues tracker at L
1108             or send them to the pdl-devel mailing list
1109             (see L).
1110              
1111              
1112             =head1 COPYRIGHT
1113              
1114             Copyright (c) 2001, 2002 Christian Soeller. All Rights Reserved.
1115             This module is free software. It may be used, redistributed
1116             and/or modified under the same terms as PDLA itself
1117             (see L).
1118              
1119             =cut
1120              
1121             1;