2014-03-30 00:56:20 +04:00
|
|
|
(in types.ps\n) print
|
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% General functions
|
|
|
|
|
2014-03-30 00:56:20 +04:00
|
|
|
% concatenate: concatenate two strings or two arrays
|
|
|
|
% From Thinking in PostScript 1990 Reid
|
|
|
|
% (string1) (string2) concatenate string3
|
|
|
|
% array1 array2 concatenate array3
|
|
|
|
/concatenate { %def
|
|
|
|
dup type 2 index type 2 copy ne { %if
|
|
|
|
pop pop
|
2014-04-02 06:50:24 +04:00
|
|
|
errordict begin (concatenate) typecheck end
|
2014-03-30 00:56:20 +04:00
|
|
|
}{ %else
|
|
|
|
/stringtype ne exch /arraytype ne and {
|
|
|
|
errordict begin (concatenate) typecheck end
|
|
|
|
} if
|
|
|
|
} ifelse
|
|
|
|
dup length 2 index length add 1 index type
|
|
|
|
/arraytype eq { array }{ string } ifelse
|
|
|
|
% stack: arg1 arg2 new
|
|
|
|
dup 0 4 index putinterval
|
|
|
|
% stack: arg1 arg2 new
|
|
|
|
dup 4 -1 roll length 4 -1 roll putinterval
|
|
|
|
% stack: new
|
|
|
|
} bind def
|
|
|
|
|
2014-03-30 02:01:24 +04:00
|
|
|
% reverse: array1 -> reverse -> array2
|
|
|
|
/reverse {
|
|
|
|
[ exch
|
|
|
|
aload % push array onto stack
|
|
|
|
length -1 0 { 1 roll } for % reverse
|
|
|
|
]
|
2014-03-30 02:35:53 +04:00
|
|
|
} bind def
|
2014-03-30 02:01:24 +04:00
|
|
|
|
2014-03-30 03:20:07 +04:00
|
|
|
% objA objB -> _equal? -> bool
|
|
|
|
/_equal? { 6 dict begin
|
|
|
|
/b exch def
|
|
|
|
/a exch def
|
|
|
|
/ota a type def
|
|
|
|
/otb b type def
|
|
|
|
|
|
|
|
a type b type eq
|
|
|
|
a _list? b _list? and
|
|
|
|
or not { %if type mismatch and not sequential
|
|
|
|
false
|
|
|
|
}{
|
|
|
|
a _list? { %if list
|
|
|
|
/ret true def
|
|
|
|
a length b length eq not { %if length mismatch
|
|
|
|
/ret false def
|
|
|
|
}{ %else (length is the same)
|
|
|
|
0 1 a length 1 sub {
|
|
|
|
/idx exch def
|
|
|
|
a idx get b idx get _equal? not { %if not items _equal?
|
|
|
|
/ret false def
|
|
|
|
exit
|
|
|
|
} if
|
|
|
|
} for
|
|
|
|
} ifelse
|
|
|
|
ret
|
|
|
|
}{ %else not a list
|
|
|
|
a b eq
|
|
|
|
} ifelse
|
|
|
|
} ifelse
|
|
|
|
end } def
|
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_sequential? { _list? } def
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_first {
|
|
|
|
dup length 0 gt { 0 get }{ pop null } ifelse
|
2014-03-31 07:39:44 +04:00
|
|
|
} def
|
2014-04-03 07:23:37 +04:00
|
|
|
/_rest {
|
|
|
|
dup length 0 gt {
|
|
|
|
dup length 1 sub 1 exch getinterval
|
2014-04-01 08:05:41 +04:00
|
|
|
}{
|
2014-04-03 07:23:37 +04:00
|
|
|
pop 0 array
|
2014-04-01 08:05:41 +04:00
|
|
|
} ifelse
|
|
|
|
} def
|
|
|
|
|
2014-03-30 02:35:53 +04:00
|
|
|
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-03-31 07:39:44 +04:00
|
|
|
% Errors/Exceptions
|
2014-03-30 00:56:20 +04:00
|
|
|
|
2014-03-30 02:35:53 +04:00
|
|
|
/errorinfo? {
|
|
|
|
$error /errorinfo known { % if set
|
|
|
|
$error /errorinfo get null ne {
|
|
|
|
true
|
|
|
|
}{
|
|
|
|
false
|
|
|
|
} ifelse
|
|
|
|
}{
|
|
|
|
false
|
|
|
|
} ifelse
|
2014-03-30 00:56:20 +04:00
|
|
|
} def
|
2014-03-30 02:26:07 +04:00
|
|
|
|
2014-03-30 02:35:53 +04:00
|
|
|
/get_error_data {
|
|
|
|
errorinfo? { %if
|
|
|
|
$error /errorinfo get
|
|
|
|
}{
|
|
|
|
$error /errorname get 255 string cvs
|
|
|
|
(: )
|
|
|
|
$error /command get 99 string cvs
|
|
|
|
( at )
|
|
|
|
$error /position get 10 99 string cvrs
|
|
|
|
concatenate
|
|
|
|
concatenate
|
|
|
|
concatenate
|
|
|
|
concatenate
|
|
|
|
} ifelse
|
|
|
|
} def
|
2014-03-30 02:26:07 +04:00
|
|
|
|
2014-03-30 02:35:53 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% Scalars
|
2014-03-30 02:35:53 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_nil? { null eq } def
|
|
|
|
/_true? { true eq } def
|
|
|
|
/_false? { false eq } def
|
2014-03-30 02:26:07 +04:00
|
|
|
|
2014-03-31 07:39:44 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% Symbols
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_symbol? {
|
|
|
|
type /nametype eq
|
2014-03-31 07:39:44 +04:00
|
|
|
} def
|
|
|
|
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% Functions
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_mal_function? {
|
|
|
|
dup type /dicttype eq {
|
|
|
|
/type get /_maltype_function eq
|
|
|
|
}{
|
|
|
|
pop false
|
|
|
|
} ifelse
|
|
|
|
} def
|
2014-04-02 06:50:24 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% args mal_function -> fload -> ast new_env
|
|
|
|
% fload: sets up arguments on the stack for an EVAL call
|
|
|
|
/fload {
|
|
|
|
dup /ast get 3 1 roll % stack: ast args mal_function
|
|
|
|
dup /env get 3 1 roll % stack: ast env args mal_function
|
|
|
|
/params get exch % stack: ast env params args
|
|
|
|
env_new % stack: ast new_env
|
|
|
|
} def
|
2014-03-30 02:26:07 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% function_or_block -> callable -> block
|
|
|
|
% if this is a user defined mal function, get its executable block
|
|
|
|
/callable { dup _mal_function? { /data get } if } def
|
2014-03-30 02:26:07 +04:00
|
|
|
|
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
% Lists
|
2014-03-30 02:26:07 +04:00
|
|
|
|
2014-04-03 07:23:37 +04:00
|
|
|
/_list {
|
|
|
|
array astore
|
|
|
|
} def
|
|
|
|
/_list? {
|
|
|
|
dup xcheck not exch type /arraytype eq and
|
|
|
|
} def
|
|
|
|
/_nth { get } def
|
2014-03-30 03:20:07 +04:00
|
|
|
|