make, swift3: fix parsing empty literal sequences.
[jackhill/mal.git] / ps / step3_env.ps
1 /runlibfile where { pop }{ /runlibfile { run } def } ifelse %
2 (types.ps) runlibfile
3 (reader.ps) runlibfile
4 (printer.ps) runlibfile
5 (env.ps) runlibfile
6
7 % read
8 /_readline { print flush (%stdin) (r) file 1024 string readline } def
9
10 /READ {
11 /str exch def
12 str read_str
13 } def
14
15
16 % eval
17 /eval_ast { 2 dict begin
18 /env exch def
19 /ast exch def
20 %(eval_ast: ) print ast ==
21 ast _symbol? { %if symbol
22 env ast env_get
23 }{ ast _sequential? { %elseif list or vector
24 [
25 ast /data get { %forall items
26 env EVAL
27 } forall
28 ] ast _list? { _list_from_array }{ _vector_from_array } ifelse
29 }{ ast _hash_map? { %elseif list or vector
30 <<
31 ast /data get { %forall entries
32 env EVAL
33 } forall
34 >> _hash_map_from_dict
35 }{ % else
36 ast
37 } ifelse } ifelse } ifelse
38 end } def
39
40 /EVAL { 8 dict begin
41 /env exch def
42 /ast exch def
43
44 %(EVAL: ) print ast true _pr_str print (\n) print
45 ast _list? not { %if not a list
46 ast env eval_ast
47 }{ %else apply the list
48 /a0 ast 0 _nth def
49 a0 _nil? { %if ()
50 ast
51 }{ /def! a0 eq { %if def!
52 /a1 ast 1 _nth def
53 /a2 ast 2 _nth def
54 env a1 a2 env EVAL env_set
55 }{ /let* a0 eq { %if let*
56 /a1 ast 1 _nth def
57 /a2 ast 2 _nth def
58 /let_env env null null env_new def
59 0 2 a1 _count 1 sub { %for each pair
60 /idx exch def
61 let_env
62 a1 idx _nth
63 a1 idx 1 add _nth let_env EVAL
64 env_set
65 pop % discard the return value
66 } for
67 a2 let_env EVAL
68 }{
69 /el ast env eval_ast def
70 el _rest el _first % stack: ast function
71 exec % apply function to args
72 } ifelse } ifelse } ifelse
73 } ifelse
74 end } def
75
76
77 % print
78 /PRINT {
79 true _pr_str
80 } def
81
82
83 % repl
84 /repl_env null null null env_new def
85
86 /REP { READ repl_env EVAL PRINT } def
87
88 /_ref { repl_env 3 1 roll env_set pop } def
89 (+) { dup 0 _nth exch 1 _nth add } _ref
90 (-) { dup 0 _nth exch 1 _nth sub } _ref
91 (*) { dup 0 _nth exch 1 _nth mul } _ref
92 (/) { dup 0 _nth exch 1 _nth idiv } _ref
93
94 % repl loop
95 { %loop
96 (user> ) _readline
97 not { exit } if % exit if EOF
98
99 { %try
100 REP print (\n) print
101 } stopped {
102 (Error: ) print
103 get_error_data false _pr_str print (\n) print
104 $error /newerror false put
105 $error /errorinfo null put
106 clear
107 cleardictstack
108 } if
109 } bind loop
110
111 (\n) print % final newline before exit for cleanliness
112 quit