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
(concatenate
) 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 obj _mal_function?
{ % if user defined function
40 obj
/params get print_readably _pr_str
42 obj
/ast get print_readably _pr_str
44 concatenate concatenate concatenate concatenate
45 }{ /arraytype obj type eq
{ % if list or code block
46 % accumulate an array of strings
47 func?
{ (<builtin_fn
* { ) }{ (\
() } ifelse
48 obj
( ) print_readably _pr_str_args
50 func?
{ ( } >) }{ (\
)) } ifelse
52 }{ /integertype obj type eq
{ % if number
53 /slen obj
10 add
log ceiling cvi def
54 obj
10 slen string cvrs
55 }{ /stringtype obj type eq
{ % if string
57 (") obj (") concatenate concatenate
61 }{ null obj eq
{ % if nil
63 }{ true obj eq
{ % if true
65 }{ false obj eq
{ % if false
67 }{ /nametype obj type eq
{ % if symbol
68 obj
dup length string cvs
71 } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse
74 % array delim print_readably -> _pr_str_args -> new_string
75 /_pr_str_args
{ 3 dict begin
76 /print_readably
exch def
80 args length
0 gt
{ %if any elements
82 args
{ %foreach argument in array
83 print_readably _pr_str
86 { concatenate delim concatenate
} forall
87 dup length delim length
sub 0 exch getinterval
% strip off final delim
91 % objA objB -> _equal? -> bool
92 /_equal?
{ 6 dict begin
100 or not
{ %if type mismatch and not sequential
105 a length b length eq not
{ %if length mismatch
107 }{ %else (length is the same)
110 a idx get b idx get _equal? not
{ %if not items _equal?
123 /_nil?
{ null eq
} def
124 /_true?
{ true eq
} def
125 /_false?
{ false eq
} def
139 dup type
/dicttype eq
{
140 /type get
/_maltype_function eq
146 % args mal_function -> fload -> ast new_env
147 % fload: sets up arguments on the stack for an EVAL call
149 dup /ast get
3 1 roll % stack: ast args mal_function
150 dup /env get
3 1 roll % stack: ast env args mal_function
151 /params get
exch % stack: ast env params args
152 env_new
% stack: ast new_env
155 % function_or_block -> callable -> block
156 % if this is a user defined mal function, get its executable block
157 /callable
{ dup _mal_function?
{ /data get
} if } def
164 % Takes an arbitrary data and puts it in $error:/errorinfo. Then calls
165 % stop to transfer control to end of nearest stopped context.
167 $error
exch /errorinfo
exch put
168 $error
/command
/throw put
173 $error
/errorinfo known
{ % if set
174 $error
/errorinfo get null ne
{
186 $error
/errorinfo get
188 $error
/errorname get
255 string cvs
190 $error
/command get
99 string cvs
192 $error
/position get
10 99 string cvrs
209 dup xcheck not
exch type
/arraytype eq and
216 lst length
1 add array
217 dup 0 elem put
% first element
218 dup 1 lst putinterval
% rest of the elements
221 /concat
{ % replaces matric concat
222 dup length
0 eq
{ %if just concat
224 }{ dup length
1 eq
{ %elseif concat of single item
235 % Sequence operations
238 dup length
0 gt
{ 0 get
}{ pop null
} ifelse
242 dup length
1 sub 1 exch getinterval
248 % [function args... arg_list] -> apply -> result
249 /apply
{ 1 dict begin
251 args
0 get callable
% make sure function is callable
252 args
1 args length
2 sub getinterval
253 args args length
1 sub get
254 concatenate args
0 get
% stack: args function
258 % function list -> _map -> new_list
261 callable
% make sure function is callable
262 %/new_list args length array def
265 exch dup 3 1 roll % stack: fn arg fn
266 exec exch % stack: result fn
268 pop % remove the function
269 args length array astore
272 /_sequential?
{ _list?
} def
276 /src_list args
0 get def
277 /new_len src_list length args length
1 sub add def
278 /new_list new_len array def
279 new_list new_len src_list length
sub src_list putinterval
280 args length
1 sub -1 1 {
282 new_list args length idx
sub 1 sub args idx get put
291 % outer binds exprs -> env_new -> new_env
292 /env_new
{ 3 dict begin
293 %(in env_new\n) print
299 0 1 binds length
1 sub {
301 binds idx get
(&) eq
{ %if &
302 binds idx
1 add get
% key
303 exprs idx exprs length idx
sub getinterval
% value
307 exprs idx get
% value
312 /env_find
{ 2 dict begin
315 env key known
{ %if key in env
317 }{ env
/__outer__ get null ne
{ %elseif __outer__ not null
318 env
/__outer__ get key env_find
324 /env_set
{ 4 dict begin
326 /func?
exch xcheck def
% executable function
330 env key val func?
{ cvx
} if put
334 /env_get
{ 2 dict begin
342 concatenate concatenate
350 % types_ns is namespace of type functions
353 (pr
-str
) { ( ) true _pr_str_args
}
354 (str
) { () false _pr_str_args
}
355 (prn
) { ( ) true _pr_str_args print
(\n) print null
}
356 (println
) { () false _pr_str_args print
(\n) print null
}
357 (=) { dup 0 get
exch 1 get _equal?
}
358 (symbol?
) { 0 get _symbol?
}
359 (nil?
) { 0 get _nil?
}
360 (true?
) { 0 get _true?
}
361 (false?
) { 0 get _false?
}
362 (<) { dup 0 get
exch 1 get lt
}
363 (<=) { dup 0 get
exch 1 get le
}
364 (>) { dup 0 get
exch 1 get gt
}
365 (>=) { dup 0 get
exch 1 get ge
}
366 (+) { dup 0 get
exch 1 get add
}
367 (-) { dup 0 get
exch 1 get
sub }
368 (*) { dup 0 get
exch 1 get
mul }
369 (/) { dup 0 get
exch 1 get
idiv }
370 (throw
) { 0 get throw
}
371 (list
) { dup pop } % noop
372 (list?
) { 0 get _list?
}
373 (cons
) { dup 0 get
exch 1 get _cons
}
375 (sequential?
) { 0 get _sequential?
}
376 (empty?
) { 0 get length
0 eq
}
377 (count) { 0 get length
}
378 (nth
) { dup 0 get
exch 1 get _nth
}
379 (first
) { 0 get _first
}
380 (rest
) { 0 get _rest
}
382 (map
) { dup 0 get
exch 1 get _map
}