File Coverage

blib/lib/PDL/NiceSlice.pm
Criterion Covered Total %
statement 199 223 89.2
branch 81 120 67.5
condition 35 75 46.6
subroutine 22 23 95.6
pod 0 14 0.0
total 337 455 74.0


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