5 % concatenate: concatenate two strings or two arrays
6 % From Thinking in PostScript 1990 Reid, Example 11.7
7 % (string1) (string2) concatenate string3
8 % array1 array2 concatenate array3
10 dup type
2 index type
2 copy ne
{ %if
12 errordict begin
(concatenate
) typecheck end
14 /stringtype ne
exch /arraytype ne and
{
15 errordict begin
(concatenate
) typecheck end
18 dup length
2 index length add
1 index type
19 /arraytype eq
{ array
}{ string
} ifelse
20 % stack: arg1 arg2 new
21 dup 0 4 index putinterval
22 % stack: arg1 arg2 new
23 dup 4 -1 roll length
4 -1 roll putinterval
27 % reverse: array1 -> reverse -> array2
30 aload
% push array onto stack
31 length
-1 0 { 1 roll } for % reverse
35 % string1 string2 string3 -> replace -> string4
36 % Return a string4 with all occurrences of string2 in string1 replaced
38 /replace
{ 4 dict begin
44 haystack needle search
46 % stack: post match pre
47 repstr concatenate
3 1 roll pop % stack: pre+ post
48 /haystack
exch def
% stack: pre+
49 result
exch concatenate
/result
exch def
51 result
exch concatenate
/result
exch def
59 % objA objB -> _equal? -> bool
60 /_equal?
{ 6 dict begin
67 a _sequential? b _sequential? and
68 or not
{ %if type mismatch and not sequential
71 a _sequential?
{ %if list
73 a _count b _count eq not
{ %if length mismatch
75 }{ %else (length is the same)
78 a idx _nth b idx _nth _equal? not
{ %if not items _equal?
92 % Low-level sequence operations
94 /_sequential?
{ dup _list?
exch _vector? or
} def
96 /_count
{ /data get length
} def
100 dup length
0 gt
{ 0 get
}{ pop null
} ifelse
103 % seq start count -> _slice -> new_seq
105 3 -1 roll /data get
3 1 roll % stack: array start count
110 % seq idx -> _nth -> ith_item
112 exch /data get
% stack: idx array
113 dup length
0 gt
{ exch get
}{ pop pop null
} ifelse
116 % seq -> _rest -> rest_seq
120 dup length
1 sub 1 exch getinterval
132 % Takes arbitrary data and puts it in $error:/errorinfo. Then calls
133 % stop to transfer control to end of nearest stopped context.
135 $error
exch /errorinfo
exch put
136 $error
/command
/throw put
141 $error
/errorinfo known
{ % if set
142 $error
/errorinfo get null ne
{
154 $error
/errorinfo get
156 $error
/errorname get
255 string cvs
158 $error
/command get
99 string cvs
160 $error
/position get
10 99 string cvrs
171 /_nil?
{ null eq
} def
172 /_true?
{ true eq
} def
173 /_false?
{ false eq
} def
186 dup type
/dicttype eq
{
187 /_maltype_ get
/function eq
193 % args mal_function -> fload -> ast new_env
194 % fload: sets up arguments on the stack for an EVAL call
196 dup /ast get
3 1 roll % stack: ast args mal_function
197 dup /env get
3 1 roll % stack: ast env args mal_function
198 /params get
exch % stack: ast env params args
199 env_new
% stack: ast new_env
202 % function_or_block -> callable -> block
203 % if this is a user defined mal function, get its executable block
204 /callable
{ dup _mal_function?
{ /data get
} if } def
209 % array -> _list_from_array -> mal_list
212 /data
3 -1 roll % grab the array argument
217 % elem... cnt -> _list -> mal_list
219 array astore _list_from_array
222 dup type
/dicttype eq
{
223 /_maltype_ get
/list eq
232 % array -> _vector_from_array -> mal_vector
233 /_vector_from_array
{
235 /data
3 -1 roll % grab the array argument
240 % elem... cnt -> _vector -> mal_vector
242 array astore _vector_from_array
245 dup type
/dicttype eq
{
246 /_maltype_ get
/vector eq
255 % dict -> _hash_map_from_dict -> mal_hash_map
256 /_hash_map_from_dict
{
263 % array -> _hash_map_from_array -> mal_hash_map
264 /_hash_map_from_array
{
267 4 -1 roll % grab the array argument
268 aload
pop % unpack the array
274 % elem... cnt -> _hash_map -> mal_hash_map
276 array astore _hash_map_from_array
279 dup type
/dicttype eq
{
280 /_maltype_ get
/hash_map eq
289 % obj -> atom -> new_atom
299 dup type
/dicttype eq
{
300 /_maltype_ get
/atom eq
308 % Sequence operations