TypeScript: setup initial environment
[jackhill/mal.git] / chuck / step2_eval.ck
1 // @import readline.ck
2 // @import types/boxed/*.ck
3 // @import types/MalObject.ck
4 // @import types/mal/MalAtom.ck
5 // @import types/mal/MalError.ck
6 // @import types/mal/MalNil.ck
7 // @import types/mal/MalFalse.ck
8 // @import types/mal/MalTrue.ck
9 // @import types/mal/MalInt.ck
10 // @import types/mal/MalString.ck
11 // @import types/mal/MalSymbol.ck
12 // @import types/mal/MalKeyword.ck
13 // @import types/mal/MalList.ck
14 // @import types/mal/MalVector.ck
15 // @import types/mal/MalHashMap.ck
16 // @import util/*.ck
17 // @import reader.ck
18 // @import printer.ck
19 // @import env.ck
20 // @import types/MalSubr.ck
21 // @import types/subr/*.ck
22
23 fun MalObject READ(string input)
24 {
25 return Reader.read_str(input);
26 }
27
28 fun MalObject EVAL(MalObject m, MalSubr env[])
29 {
30 if( m.type == "list" )
31 {
32 if( (m$MalList).value().size() == 0 )
33 {
34 return m;
35 }
36
37 eval_ast(m, env) @=> MalObject result;
38 if( result.type == "error" )
39 {
40 return result;
41 }
42
43 (result$MalList).value() @=> MalObject values[];
44 values[0]$MalSubr @=> MalSubr subr;
45 MalObject.slice(values, 1) @=> MalObject args[];
46
47 return subr.call(args);
48 }
49 else
50 {
51 return eval_ast(m, env);
52 }
53 }
54
55 fun MalObject eval_ast(MalObject m, MalSubr env[])
56 {
57 m.type => string type;
58
59 if( type == "symbol" )
60 {
61 (m$MalSymbol).value() => string symbol;
62 env[symbol] @=> MalSubr subr;
63
64 if( subr == null )
65 {
66 return MalError.create(MalString.create("'" + symbol + "' not found"));
67 }
68 else
69 {
70 return subr;
71 }
72 }
73 else if( type == "list" || type == "vector" || type == "hashmap" )
74 {
75 (m$MalList).value() @=> MalObject values[];
76 MalObject results[values.size()];
77
78 if( type != "hashmap" )
79 {
80 for( 0 => int i; i < values.size(); i++ )
81 {
82 EVAL(values[i], env) @=> MalObject result;
83
84 if( result.type == "error" )
85 {
86 return result;
87 }
88
89 result @=> results[i];
90 }
91 }
92 else
93 {
94 for( 0 => int i; i < values.size(); i++ )
95 {
96 if( i % 2 == 0 )
97 {
98 values[i] @=> results[i];
99 }
100 else
101 {
102 EVAL(values[i], env) @=> results[i];
103 }
104 }
105 }
106
107 if( type == "list" )
108 {
109 return MalList.create(results);
110 }
111 else if( type == "vector" )
112 {
113 return MalVector.create(results);
114 }
115 else if( type == "hashmap" )
116 {
117 return MalHashMap.create(results);
118 }
119 }
120 else
121 {
122 return m;
123 }
124 }
125
126 fun string PRINT(MalObject m)
127 {
128 return Printer.pr_str(m, true);
129 }
130
131 MalSubr repl_env[0];
132 new MalAdd @=> repl_env["+"];
133 new MalSub @=> repl_env["-"];
134 new MalMul @=> repl_env["*"];
135 new MalDiv @=> repl_env["/"];
136
137 fun string errorMessage(MalObject m)
138 {
139 (m$MalError).value() @=> MalObject value;
140
141 if( value.type == "string" )
142 {
143 return Printer.pr_str(value, false);
144 }
145 else
146 {
147 return "exception: " + Printer.pr_str(value, true);
148 }
149 }
150
151 fun string rep(string input)
152 {
153 READ(input) @=> MalObject m;
154
155 if( m.type == "error" )
156 {
157 return errorMessage(m);
158 }
159
160 EVAL(m, repl_env) @=> MalObject result;
161 if( result.type == "error" )
162 {
163 return errorMessage(result);
164 }
165
166 return PRINT(result);
167 }
168
169 fun void main()
170 {
171 int done;
172
173 while( !done )
174 {
175 Readline.readline("user> ") => string input;
176
177 if( input != null )
178 {
179 rep(input) => string output;
180
181 if( output == "empty input" )
182 {
183 // proceed immediately with prompt
184 }
185 else
186 {
187 Util.println(output);
188 }
189 }
190 else
191 {
192 true => done;
193 }
194 }
195 }
196
197 main();