File Coverage

blib/lib/PDL/NiceSlice.pm
Criterion Covered Total %
statement 157 197 79.7
branch 70 120 58.3
condition 27 63 42.8
subroutine 18 20 90.0
pod 1 14 7.1
total 273 414 65.9


line stmt bran cond sub pod time code
1             BEGIN {
2 123     123   981 my %engine_ok = (
3             'Filter::Util::Call' => 'PDL/NiceSlice/FilterUtilCall.pm',
4             'Filter::Simple' => 'PDL/NiceSlice/FilterSimple.pm',
5             'Module::Compile' => 'PDL/NiceSlice/ModuleCompile.pm',
6             ); # to validate names
7              
8             ## $PDL::NiceSlice::engine = $engine_ok{'Filter::Simple'}; # default engine type
9             ## TODO: Add configuration argument to perldl.conf
10 123         338 $PDL::NiceSlice::engine = $engine_ok{'Filter::Util::Call'}; # default engine type
11              
12 123 50       3898 if ( exists $ENV{PDL_NICESLICE_ENGINE} ) {
13 0         0 my $engine = $ENV{PDL_NICESLICE_ENGINE};
14 0 0 0     0 if ( exists $engine_ok{$engine} and $engine_ok{$engine} ) {
    0 0        
15 0         0 $PDL::NiceSlice::engine = $engine_ok{$engine};
16 0 0       0 warn "PDL::NiceSlice using engine '$engine'\n" if $PDL::verbose;
17             } elsif ( exists $engine_ok{$engine} and not $engine_ok{$engine} ) {
18 0 0       0 warn "PDL::NiceSlice using default engine\n" if $PDL::verbose;
19             } else {
20 0         0 die "PDL::NiceSlice: PDL_NICESLICE_ENGINE set to invalid engine '$engine'\n";
21             }
22             }
23             }
24              
25 123     123   707 no warnings;
  123         253  
  123         15468  
26              
27             package PDL::NiceSlice;
28              
29             our $VERSION = '1.001';
30             $VERSION = eval $VERSION;
31              
32             $PDL::NiceSlice::debug = defined($PDL::NiceSlice::debug) ? $PDL::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+PDL\;:\;:NiceSlice\;\s*$/.
47              
48             # the next one is largely stolen from Regexp::Common
49             my $RE_cmt = qr'(?:(?:\#)(?:[^\n]*)(?:\n))';
50              
51             require PDL::Version; # get PDL version number
52             #
53             # remove code for PDL versions earlier than 2.3
54             #
55              
56 123     123   90660 use Text::Balanced; # used to find parenthesis-delimited blocks
  123         2096081  
  123         8486  
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 123     123   1218 no warnings; # quiet warnings for this
  123     0   287  
  123         337818  
66              
67             sub Text::Balanced::extract_quotelike (;$$)
68             {
69 2 50   2 1 81887 my $textref = $_[0] ? \$_[0] : \$_;
70 2         6 my $wantarray = wantarray;
71 2 50       12 my $pre = defined $_[1] ? $_[1] : '\s*';
72            
73 2         10 my @match = Text::Balanced::_match_quotelike($textref,$pre,0,0); # do not match // alone as m//
74 2 50       663 return Text::Balanced::_fail($wantarray, $textref) unless @match;
75 2         13 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 4 my $arg = $callstack[-1]; # return top element of stack
91 2         13 $arg =~ s/\((.*)\)/$1/s;
92 2         25 return $arg;
93             }
94 4848     4848 0 10075 sub savearg ($) {push @callstack,$_[0]}
95 1038     1038 0 1755 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 5 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         5  
  2         6  
114 2         10 return ($pretext =~ tr/\n/\n/)+$offset;
115             }
116              
117             sub filterdie {
118 2     2 0 10 my ($msg) = @_;
119 2         10 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 12216     12216 0 22358 my ($re,$txt) = @_;
131 12216         19672 my ($got,$pre) = (1,'');
132 12216         19574 my @chunks = ('');
133 12216         15248 my $ct = 0; # infinite loop protection
134 12216   66     53164 while ($got && $txt =~ /[({\[]/ && $ct++ < 1000) {
      66        
135             # print "iteration $ct\n";
136 6547         15866 ($got,$txt,$pre) =
137             Text::Balanced::extract_bracketed($txt,'{}()[]',$prebrackreg);
138 6547         897357 my @partialargs = split $re, $pre, -1;
139 6547 100       19344 $chunks[-1] .= shift @partialargs if @partialargs;
140 6547         10419 push @chunks, @partialargs;
141 6547         31703 $chunks[-1] .= $got;
142             }
143 12216 50       23271 filterdie "possible infinite parse loop, slice arg '".curarg()."'"
144             if $ct == 1000;
145 12216         92631 my @partialargs = split $re, $txt, -1;
146 12216 100       34029 $chunks[-1] .= shift @partialargs if @partialargs;
147 12216         19971 push @chunks, @partialargs;
148 12216         31865 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 7326     7326 0 12324 my ($arg) = @_;
170 7326 50       12518 print STDERR "processing arg '$arg'\n" if $PDL::NiceSlice::debug;
171 7326 100       23943 return q|'X'| if $arg =~ /^\s*:??\s*$/; # empty arg or just colon
172             # recursively process args for slice syntax
173 7068 100       37748 $arg = findslice($arg,$PDL::debug) if $arg =~ $prefixpat;
174             # no doubles colon are matched to avoid confusion with Perl's C<::>
175 7068 100       17784 if ($arg =~ /(?
176 2522         4855 my @args = splitprotected '(?
177 2522 50       6053 filterdie "invalid range in slice expression '".curarg()."'"
178             if @args > 3;
179 2522 50 33     11621 $args[0] = 0 if !defined $args[0] || $args[0] =~ /^\s*$/;
180 2522 50 33     9500 $args[1] = -1 if !defined $args[1] || $args[1] =~ /^\s*$/;
181 2522 100 66     6699 $args[2] = undef if !defined $args[2] || $args[2] =~ /^\s*$/;
182 2522         11891 return "[".join(',',@args)."]"; # replace single ':' with ','
183             }
184             # the (pos) syntax, i.e. 0D slice
185 4546 100       26118 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 1279 50       3016 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 1279 100       4053 return "(q(*).($arg))" if($arg =~ s/^\s*\*//);
193              
194             # this must be a simple position, leave as is
195 1033         3513 return "$arg";
196             }
197              
198             # process the arg list
199             sub procargs {
200 4846     4846 0 9276 my ($txt) = @_;
201 4846 50       8435 print STDERR "procargs: got '$txt'\n" if $PDL::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 4846 50       17901 join ',', map {onearg $_} splitprotected ',', $txt;
  7326         14090  
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 4846 50       11173 print STDERR "procargs: returned '($args)'\n" if $PDL::NiceSlice::debug;
214 4846         11140 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 1040     1040 0 6905 my ($src,$verb) = @_;
222 1040         2615 push @srcstr, \$src;
223 1040 100       2910 $verb = 0 unless defined $verb;
224 1040         1913 my $processed = '';
225 1040         1557 my $ct=0; # protect against infinite loop
226 1040         1724 my ($found,$prefix,$dummy);
227 1040   66     109630 while ( $src =~ m/\G($prefixpat)/ && (($found,$dummy,$prefix) =
      66        
228             Text::Balanced::extract_bracketed($src,'()',$prefixpat))[0]
229             && $ct++ < 1000) {
230 5596 50       1399762 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 5596 100 100     61536 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 748         3439 $processed .= "$prefix".findslice($found);
245             } else { # statement is a real slice and not a foreach
246              
247 4848         8916 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 4848         11432 savearg $found; # error reporting
253 4848 50       9229 print STDERR "findslice: found '$found'\n" if $PDL::NiceSlice::debug;
254 4848         23999 $found =~ s/^\s*\((.*)\)\s*$/$1/s;
255 4848         11687 my ($slicearg,@mods) = splitprotected ';', $found;
256 4848 50       10468 filterdie "more than 1 modifier group: @mods" if @mods > 1;
257             # filterdie "invalid modifier $1"
258             # if $found =~ /(;\s*[[:graph:]]{2,}?\s*)\)$/;
259 4848 50       13510 print STDERR "MODS: " . join(',',@mods) . "\n" if $PDL::NiceSlice::debug;
260 4848         9647 my @post = (); # collects all post slice operations
261 4848         6729 my @pre = ();
262 4848 100       8653 if (@mods) {
263 7         25 (my $mod = $mods[0]) =~ s/\s//sg; # eliminate whitespace
264 7         18 my @modflags = split '', $mod;
265 7 50       14 print STDERR "MODFLAGS: @modflags\n" if $PDL::NiceSlice::debug;
266 7 100 100     41 filterdie "more than 1 modifier incompatible with ?: @modflags"
267             if @modflags > 1 && grep (/\?/, @modflags); # only one flag with where
268 6         11 my %seen = ();
269 6 100       12 if (@modflags) {
270 5         9 for my $mod1 (@modflags) {
271 9 100       37 if ($mod1 eq '?') {
    100          
    100          
    50          
272 1 50       4 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
273 1         3 $call = 'where';
274 1         52 $arg = "(" . findslice($slicearg) . ")";
275             # $post = ''; # no post action required
276             } elsif ($mod1 eq '_') {
277 1 50       4 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
278 1         3 push @pre, 'flat->';
279 1   50     7 $call ||= 'slice'; # do only once
280 1         3 $arg = procargs($slicearg);
281             # $post = ''; # no post action required
282             } elsif ($mod1 eq '|') {
283 4 100       14 $seen{$mod1}++ && filterdie "modifier $mod1 used twice or more";
284 3   50     8 $call ||= 'slice';
285 3   33     5 $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     19 $call ||= 'slice';
290 3   33     14 $arg ||= procargs($slicearg);
291 3         11 push @post, '->reshape(-1)';
292             } else {
293 0         0 filterdie "unknown modifier $mod1";
294             }
295             }
296             } else { # empty modifier block
297 1         5 $call = 'slice';
298 1         3 $arg = procargs($slicearg);
299             # $post = '';
300             }
301             } else { # no modifier block
302 4841         6942 $call = 'slice';
303 4841         11728 $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 4846         8864 $pre = join '', @pre;
312             # assumption here: sever should be last
313             # and order of other modifiers doesn't matter
314 4846         9118 $post = join '', sort @post; # need to ensure that sever is last
315 4846 100       476078 $processed .= "$prefix". ($prefix =~ /->(\s*$RE_cmt*)*$/ ?
316             '' : '->').
317             $pre.$call.$arg.$post.$mypostfix;
318             }
319              
320             } # end of while loop
321              
322 1038         3310 poparg; # clean stack
323 1038         1703 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 1038 100       26126 $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 131     131 0 322 my $clstr = shift;
335 131         1527 $clstr =~ s/([^a-zA-Z0-9])/\\$1/g;
336 131         543 my $termstr = '^\s*no\s+'.$clstr.'\s*;\s*(#.*)*$';
337 131         3061 return qr/$termstr/o; # allow trailing comments
338             }
339              
340             sub reinstator_regexp{
341 1     1 0 2 my $clstr = shift;
342 1         21 $clstr =~ s/([^a-zA-Z0-9])/\\$1/g;
343 1         5 my $reinstr = '^\s*use\s+'.$clstr.'\s*;\s*(#.*)*$';
344 1         37 return qr/$reinstr/o; # allow trailing comments
345             }
346              
347             # save eval of findslice that should be used within perldl or pdl2
348             # as a preprocessor
349             sub perldlpp {
350 1     1 0 8 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 PDL::AutoLoader, but one never
355             # knows....
356             # -- CED 5-Nov-2007
357 1 50       5 if(!defined($txt)) {
358 0         0 print "PDL::NiceSlice::perldlpp -- got deprecated one-argument form, from ".(join("; ",caller))."...\n";
359 0         0 $txt = $class;
360 0         0 $class = "PDL::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($PDL::debug > 1) {
365 0         0 print "PDL::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         3 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         9 my @lines= split /\n/,$txt;
382              
383 1         6 my $terminator = terminator_regexp($class);
384 1         4 my $reinstator = reinstator_regexp($class);
385              
386 1         3 my($status, $off, $end);
387 1         2 eval {
388 1   33     2 do {
389 1         3 my $data = "";
390 1         4 while(@lines) {
391 12         16 $_= shift @lines;
392 12 50 33     47 if(defined($terminator) && m/$terminator/) {
393 0         0 $_ = "## $_";
394 0         0 $off = 1;
395 0         0 last;
396             }
397 12 50 33     63 if(defined($reinstator) && m/$reinstator/) {
398 0         0 $_ = "## $_";
399             }
400 12 50       27 if(m/^\s*(__END__|__DATA__)\s*$/) {
401 0         0 $end=$1; $off = 1;
  0         0  
402 0         0 last;
403             }
404 12         18 $data .= "$_\n";
405 12         14 $count++;
406 12         25 $_="";
407             }
408 1         3 $_ = $data;
409 1         16 $_ = 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     8 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($PDL::debug > 1) {
441 0         0 print "PDL::NiceSlice::perldlpp - returning:\n$new\n";
442             }
443 1         8 return $new;
444             }
445              
446             BEGIN {
447 123     123   68306 require "$PDL::NiceSlice::engine";
448             }
449              
450             =head1 NAME
451              
452             PDL::NiceSlice - toward a nicer slicing syntax for PDL
453              
454             =head1 SYNOPSYS
455              
456             use PDL::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 PDL'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 perldl or pdl2 shell, but (to avoid
488             conflicts with other modules) must be loaded explicitly in standalone
489             perl/PDL 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 PDL::NiceSlice;
509              
510             # this code will be translated
511             # and you can use the new slicing syntax
512              
513             no PDL::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 PDL;
528             use PDL::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 PDL::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 PDL::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 PDL::NiceSlice;
592             $y = $x(0:5);
593              
594             EOE
595             print $y;
596              
597             Instead say:
598              
599             use PDL::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 PDL 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             PDL barfed: Error in slice:Too many dims in slice
741             Caught at file /usr/local/bin/perldl, 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 PDL 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             PDL: Double D [5]
845              
846             It also provides a unique opportunity to have smileys in your code!
847             Yes, PDL 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             PDL: 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             PDL: Double D [3,4,5]
950             print $x((0))->info;
951             PDL: Double D [4,5]
952             print $x((0),:,:)->info; # a more explicit way
953             PDL: Double D [4,5]
954             print $x((0),,)->info; # similar
955             PDL: 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             PDL 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             PDL 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 Pdlpp code -- the recommended
1066             place for Inline code anyway. In that case
1067             C will have switched itself off before encountering any
1068             Pdlpp code (see above):
1069              
1070             # use with Inline modules
1071             use PDL;
1072             use PDL::NiceSlice;
1073             use Inline Pdlpp;
1074              
1075             $x = sequence(10);
1076             print $x(0:5);
1077              
1078             __END__
1079              
1080             __Pdlpp__
1081              
1082             ... inline stuff
1083              
1084              
1085             Otherwise switch C explicitly off around the
1086             Inline::Pdlpp code:
1087              
1088             use PDL::NiceSlice;
1089              
1090             $x = sequence 10;
1091             $x(0:3)++;
1092             $x->inc;
1093              
1094             no PDL::NiceSlice; # switch off before Pdlpp code
1095             use Inline Pdlpp => "Pdlpp 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 Pdlpp 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 PDL
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 PDL itself
1117             (see L).
1118              
1119             =cut
1120              
1121             1;