3 % concatenate: concatenate two strings or two arrays
4 % From Thinking in PostScript 1990 Reid
5 % (string1) (string2) concatenate string3
6 % array1 array2 concatenate array3
8 dup type
2 index type
2 copy ne
{ %if
10 errordict begin
(concatentate
) typecheck end
12 /stringtype ne
exch /arraytype ne and
{
13 errordict begin
(concatenate
) typecheck end
16 dup length
2 index length add
1 index type
17 /arraytype eq
{ array
}{ string
} ifelse
18 % stack: arg1 arg2 new
19 dup 0 4 index putinterval
20 % stack: arg1 arg2 new
21 dup 4 -1 roll length
4 -1 roll putinterval
25 % reverse: array1 -> reverse -> array2
28 aload
% push array onto stack
29 length
-1 0 { 1 roll } for % reverse
33 /_pr_str
{ 4 dict begin
34 /print_readably
exch def
36 /func?
exch xcheck def
% executable function
38 /arraytype obj type eq
{ % if list
39 % accumulate an array of strings
40 func?
{ (<fn
* { ) }{ (\
() } ifelse
41 obj
( ) print_readably _pr_str_args
43 func?
{ ( } >) }{ (\
)) } ifelse
45 }{ /integertype obj type eq
{ % if number
46 /slen obj
10 add
log ceiling cvi def
47 obj
10 slen string cvrs
48 }{ /stringtype obj type eq
{ % if string
50 (") obj (") concatenate concatenate
54 }{ null obj eq
{ % if nil
56 }{ true obj eq
{ % if true
58 }{ false obj eq
{ % if false
60 }{ /nametype obj type eq
{ % if symbol
61 obj
dup length string cvs
64 } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse
67 % array delim print_readably -> _pr_str_args -> new_string
68 /_pr_str_args
{ 3 dict begin
69 /print_readably
exch def
73 args length
0 gt
{ %if any elements
75 args
{ %foreach argument in array
76 print_readably _pr_str
79 { concatenate delim concatenate
} forall
80 dup length delim length
sub 0 exch getinterval
% strip off final delim
84 % objA objB -> _equal? -> bool
85 /_equal?
{ 6 dict begin
93 or not
{ %if type mismatch and not sequential
98 a length b length eq not
{ %if length mismatch
100 }{ %else (length is the same)
103 a idx get b idx get _equal? not
{ %if not items _equal?
122 % Takes an arbitrary data and puts it in $error:/errorinfo. Then calls
123 % stop to transfer control to end of nearest stopped context.
125 $error
exch /errorinfo
exch put
126 $error
/command
/throw put
131 $error
/errorinfo known
{ % if set
132 $error
/errorinfo get null ne
{
144 $error
/errorinfo get
146 $error
/errorname get
255 string cvs
148 $error
/command get
99 string cvs
150 $error
/position get
10 99 string cvrs
164 dup xcheck not
exch type
/arraytype eq and
166 /_first
{ 0 get
} def
167 /_rest
{ dup length
1 sub 1 exch getinterval
} def
174 % outer binds exprs -> env_new -> new_env
175 /env_new
{ 3 dict begin
176 %(in env_new\n) print
182 0 1 binds length
1 sub {
184 binds idx get
(&) eq
{ %if &
185 binds idx
1 add get
% key
186 exprs idx exprs length idx
sub getinterval
% value
190 exprs idx get
% value
195 /env_find
{ 2 dict begin
198 env key known
{ %if key in env
200 }{ env
/__outer__ get null ne
{ %elseif __outer__ not null
201 env
/__outer__ get key env_find
207 /env_set
{ 4 dict begin
209 /func?
exch xcheck def
% executable function
213 env key val func?
{ cvx
} if put
217 /env_get
{ 2 dict begin
225 concatenate concatenate
233 % types_ns is namespace of type functions
236 (pr
-str
) { ( ) true _pr_str_args
}
237 (str
) { () false _pr_str_args
}
238 (prn
) { ( ) true _pr_str_args print
(\n) print null
}
239 (println
) { () false _pr_str_args print
(\n) print null
}
240 (=) { dup 0 get
exch 1 get _equal?
}
241 (<) { dup 0 get
exch 1 get lt
}
242 (<=) { dup 0 get
exch 1 get le
}
243 (>) { dup 0 get
exch 1 get gt
}
244 (>=) { dup 0 get
exch 1 get ge
}
245 (+) { dup 0 get
exch 1 get add
}
246 (-) { dup 0 get
exch 1 get
sub }
247 (*) { dup 0 get
exch 1 get
mul }
248 (/) { dup 0 get
exch 1 get
idiv }
250 (list?
) { 0 get _list?
}
251 (empty?
) { 0 get length
0 eq
}
252 (count) { 0 get length
}