[luser- -droog <
mij...@yahoo.com>, 2014-11-15 00:43]
[...]
> There is a possible problem here. Since `bind` applies to all
> subarrays, and the user-proc has been embedded directly into this
> array.
>
> instead of
>
> > //proc exec
>
> it might be better to do
>
> //mydict /proc get exec
>
> so the procedure is not directly embedded.
>
> Applying `bind` would break code that tries to use operator names as
> variables, like
>
> {
> /length 5 def
> length dup mul % length^2
> ...
> }
>
> The executable name `length` in the second line would be replaced by
> the postscript operator if `bind` were applied.
I didn't think of that. The problem is worse, because the string is
tokenized at the time /map is executed, and by that moment the user
could have already redefined some operators (presumably he wouldn't do
that at library loading time).
/length 5 def [ 1 2 3 ] { length add } map
So, basically, inside /map, the code surrounding "<userproc> exec"
should be bound before any operator is redefined, but the "<userproc>"
should be left as-is.
One solution can be to write the code as usual (not in a string), using
placeholders for the objects. That way, it would be bound at definition
time. When /map is called, the placeholders are replaced with the
objects. Basically, doing the "({ //x }) token" thing by hand, just so
everything that isn't a //name can be bound at definition time.
Here is a new version of map that uses that approach, plus two helper
procedures:
% <array/string> <proc> map <new array/string>
/map {
4 dict begin
/,proc exch def
/,arr exch def
/,res ,arr length
,arr type /stringtype eq { string } { array } ifelse
def
/,i 1 array def
{
0 1 /,arr length 1 sub { % for
dup /,i 0 3 -1 roll put
/,arr exch get
/,proc exec
/,res /,i 0 get 3 -1 roll put
} for
/,res
} deepcopy dup currentdict replaceall
end exec
} bind def
% copies array recursively
% <array> deepcopy <new array>
/deepcopy {
dup xcheck exch
dup length array copy
dup length 1 sub 0 exch 1 exch { % for % a i
2 copy 2 copy get dup type /arraytype eq % a i a i e ?
{ % ifelse
deepcopy put
}
{
pop pop pop
} ifelse
pop
} for
exch { cvx } if
} bind def
% recursively replaces elements in <array> found in <dict>
% <array> <dict> replaceall -
/replaceall {
1 index length 1 sub 0 1 3 -1 roll { % for 0 1 length-1
3 copy 3 -1 roll exch % a d i d a i
get % a d i d e
2 copy known % a d i d e ?
% ifelse
{ % a d i d e
get % a d i v
3 index 3 1 roll % a d a i v
put
} % else
{ % a d i d e
dup type /arraytype eq % a d i d e ?
{ exch replaceall }
{ pop pop } ifelse
pop
} ifelse % a d
} for
pop pop
} bind def
Carlos.
--