aboutsummaryrefslogtreecommitdiff
path: root/ps/printer.ps
blob: 52d6c1ece2b708e560aab8aa8e84912727706689 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
% requires types.ps to be included first

% ast print_readably -> _pr_str -> string
/_pr_str { 4 dict begin
    /print_readably exch def
    dup xcheck { (Cannot print proc: ) print dup == quit } if % assert
    /obj exch def
    obj _sequential? {
        obj _list? { (\() (\)) }{ ([) (]) } ifelse
        obj /data get ( ) print_readably _pr_str_args
        exch concatenate concatenate
    }{ obj _hash_map? {
        ({)
        % get array of contents with keys stringified
        [ obj /data get { exch dup length string cvs exch } forall ]
        ( ) print_readably _pr_str_args
        concatenate
        (}) concatenate
    }{ obj _function? { % if builtin function
        (<\(builtin_fn* {)
        obj /data get dup length array copy cvlit
        ( ) print_readably _pr_str_args
        (}>)
        concatenate concatenate
    }{ obj _mal_function? { % if user defined mal_function
        (<\(fn* )
        obj /params get print_readably _pr_str
        ( )
        obj /ast get print_readably _pr_str
        (\)>)
        concatenate concatenate concatenate concatenate
    }{ obj _atom? { % if atom
        (\(atom ) 
        obj /data get print_readably _pr_str
        (\))
        concatenate concatenate
    }{ /arraytype obj type eq { % if list or code block
        % accumulate an array of strings
        (\()
        obj ( ) print_readably _pr_str_args
        concatenate
        (\))
        concatenate
    }{ /integertype obj type eq { % if number
        /slen obj 10 add log ceiling cvi def
        obj 10 slen string cvrs
    }{ /stringtype obj type eq { % if string
        obj length 0 gt { % if string length > 0
            obj 0 get 127 eq { %if starts with 0x7f (keyword)
                obj dup length string copy
                dup 0 58 put % 58 is ':'
            }{ print_readably {
                (")
                obj (\\) (\\\\) replace
                    (") (\\") replace
                (") concatenate concatenate
            }{
                obj
            } ifelse } ifelse
        }{ % else empty string
            print_readably {
                ("")
            }{
                obj
            } ifelse
        } ifelse
    }{ null obj eq { % if nil
        (nil)
    }{ true obj eq { % if true
        (true)
    }{ false obj eq { % if false
        (false)
    }{ /nametype obj type eq { % if symbol
        obj dup length string cvs
    }{
        (<unknown>)  
    } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse
end } def

% array delim print_readably -> _pr_str_args -> new_string
/_pr_str_args { 3 dict begin
    /print_readably exch def
    /delim exch def
    /args exch def
    ()
    args length 0 gt { %if any elements
        [
            args { %foreach argument in array
                dup xcheck { %if executable
                    255 string cvs
                }{
                    print_readably _pr_str
                } ifelse
            } forall 
        ]
        { concatenate delim concatenate } forall
        dup length delim length sub 0 exch getinterval % strip off final delim
    } if
end } def

% utility function
/print_dict {
    (DICT contents:\n) print
    {
        (  - ) print
        exch dup length string cvs print % key
        (: ) print
        ==
    } forall
} def