1 /runlibfile where
{ pop }{ /runlibfile
{ run
} def
} ifelse %
4 (printer.ps
) runlibfile
9 /_readline
{ print flush
(%stdin) (r) file 1024 string readline } def
18 /eval_ast
{ 2 dict begin
21 %(eval_ast: ) print ast ==
22 ast _symbol?
{ %if symbol
24 }{ ast _sequential?
{ %elseif list or vector
26 ast
/data get
{ %forall items
29 ] ast _list?
{ _list_from_array
}{ _vector_from_array
} ifelse
30 }{ ast _hash_map?
{ %elseif list or vector
32 ast
/data get
{ %forall entries
35 >> _hash_map_from_dict
38 } ifelse } ifelse } ifelse
48 %(EVAL: ) print ast true _pr_str print (\n) print
49 ast _list? not
{ %if not a list
51 }{ %else apply the list
55 }{ /def
! a0 eq
{ %if def!
58 env a1 a2 env EVAL env_set
59 }{ /let
* a0 eq
{ %if let*
62 /let_env env null null env_new def
63 0 2 a1 _count
1 sub { %for each pair
67 a1 idx
1 add _nth let_env EVAL
69 pop % discard the return value
73 /loop?
true def
% loop
75 ast _count
2 gt
{ %if ast has more than 2 elements
76 ast
1 ast _count
2 sub _slice env eval_ast
pop
78 ast ast _count
1 sub _nth
% last ast becomes new ast
80 /loop?
true def
% loop
84 cond null eq cond
false eq or
{ % if cond is nil or false
85 ast _count
3 gt
{ %if false branch with a3
88 }{ % else false branch with no a3
95 }{ /fn
* a0 eq
{ %if fn*
98 a2 env a1 _mal_function
100 /el ast env eval_ast def
101 el _rest el _first
% stack: ast function
102 dup _mal_function?
{ %if user defined function
103 fload
% stack: ast new_env
105 }{ dup _function?
{ %else if builtin function
107 }{ %else (regular procedure/function)
108 (cannot apply native proc
!\n) print
quit
110 } ifelse } ifelse } ifelse } ifelse } ifelse } ifelse
113 loop? not
{ exit } if
125 /repl_env null null null env_new def
127 /RE
{ READ repl_env EVAL
} def
128 /REP
{ READ repl_env EVAL PRINT
} def
130 % core.ps: defined using postscript
131 /_ref
{ repl_env
3 1 roll env_set
pop } def
132 core_ns
{ _function _ref
} forall
133 (eval
) { 0 _nth repl_env EVAL
} _function _ref
134 (*ARGV
*) [ ] _list_from_array _ref
136 % core.mal: defined using the language itself
137 (\
(def
! not \
(fn
* \
(a\
) \
(if a
false true\
)\
)\
)) RE
pop
138 (\
(def
! load
-file \
(fn
* \
(f\
) \
(eval \
(read
-string \
(str
"\(do " \
(slurp f\
) "\)"\
)\
)\
)\
)\
)) RE
pop
140 userdict
/ARGUMENTS known
{ %if command line arguments
141 ARGUMENTS length
0 gt
{ %if more than 0 arguments
142 (*ARGV
*) ARGUMENTS
1 ARGUMENTS length
1 sub getinterval
143 _list_from_array _ref
145 (\
(load
-file
") exch ("\
)) concatenate concatenate RE
pop
153 not
{ exit } if % exit if EOF
159 get_error_data
false _pr_str print
(\n) print
160 $error
/newerror
false put
161 $error
/errorinfo null put
167 (\n) print
% final newline before exit for cleanliness