bbc-basic: Slight tweak to heap size.
[jackhill/mal.git] / haxe / Step3_env.hx
1 import Compat;
2 import types.Types.MalType;
3 import types.Types.*;
4 import reader.*;
5 import printer.*;
6 import env.*;
7
8 class Step3_env {
9 // READ
10 static function READ(str:String):MalType {
11 return Reader.read_str(str);
12 }
13
14 // EVAL
15 static function eval_ast(ast:MalType, env:Env) {
16 return switch (ast) {
17 case MalSymbol(s): env.get(ast);
18 case MalList(l):
19 MalList(l.map(function(x) { return EVAL(x, env); }));
20 case MalVector(l):
21 MalVector(l.map(function(x) { return EVAL(x, env); }));
22 case MalHashMap(m):
23 var new_map = new Map<String,MalType>();
24 for (k in m.keys()) {
25 new_map[k] = EVAL(m[k], env);
26 }
27 MalHashMap(new_map);
28 case _: ast;
29 }
30 }
31
32 static function EVAL(ast:MalType, env:Env):MalType {
33 if (!list_Q(ast)) { return eval_ast(ast, env); }
34
35 // apply
36 var alst = switch (ast) { case MalList(lst): lst; case _: []; }
37 if (alst.length == 0) { return ast; }
38
39 switch (alst[0]) {
40 case MalSymbol("def!"):
41 return env.set(alst[1], EVAL(alst[2], env));
42 case MalSymbol("let*"):
43 var let_env = new Env(env);
44 switch (alst[1]) {
45 case MalList(l) | MalVector(l):
46 for (i in 0...l.length) {
47 if ((i%2) > 0) { continue; }
48 let_env.set(l[i], EVAL(l[i+1], let_env));
49 }
50 case _: throw "Invalid let*";
51 }
52 return EVAL(alst[2], let_env);
53 case _:
54 var el = eval_ast(ast, env);
55 var lst = _list(el);
56 switch (first(el)) {
57 case MalFunc(f,_,_,_,_,_): return f(_list(el).slice(1));
58 case _: throw "Call of non-function";
59 }
60 }
61 }
62
63 // PRINT
64 static function PRINT(exp:MalType):String {
65 return Printer.pr_str(exp, true);
66 }
67
68 // repl
69 static function NumOp(op):MalType {
70 return MalFunc(function(args:Array<MalType>) {
71 return switch (args) {
72 case [MalInt(a), MalInt(b)]: MalInt(op(a,b));
73 case _: throw "Invalid numeric op call";
74 }
75
76 },null,null,null,false,nil);
77 }
78 static var repl_env = new Env(null);
79
80 static function rep(line:String):String {
81 return PRINT(EVAL(READ(line), repl_env));
82 }
83
84 public static function main() {
85 repl_env.set(MalSymbol("+"), NumOp(function(a,b) {return a+b;}));
86 repl_env.set(MalSymbol("-"), NumOp(function(a,b) {return a-b;}));
87 repl_env.set(MalSymbol("*"), NumOp(function(a,b) {return a*b;}));
88 repl_env.set(MalSymbol("/"), NumOp(function(a,b) {return Std.int(a/b);}));
89 while (true) {
90 try {
91 var line = Compat.readline("user> ");
92 if (line == "") { continue; }
93 Compat.println(rep(line));
94 } catch (exc:BlankLine) {
95 continue;
96 } catch (exc:haxe.io.Eof) {
97 Compat.exit(0);
98 } catch (exc:Dynamic) {
99 Compat.println("Error: " + exc);
100 }
101 }
102 }
103 }