forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStep2_eval.hx
92 lines (82 loc) · 2.77 KB
/
Step2_eval.hx
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
import Compat;
import types.Types.MalType;
import types.Types.*;
import reader.*;
import printer.*;
class Step2_eval {
// READ
static function READ(str:String):MalType {
return Reader.read_str(str);
}
// EVAL
static function eval_ast(ast:MalType, env:Map<String,MalType>) {
return switch (ast) {
case MalSymbol(s):
if (env.exists(s)) {
env.get(s);
} else {
throw "'" + s + "' not found";
}
case MalList(l):
MalList(l.map(function(x) { return EVAL(x, env); }));
case MalVector(l):
MalVector(l.map(function(x) { return EVAL(x, env); }));
case MalHashMap(m):
var new_map = new Map<String,MalType>();
for (k in m.keys()) {
new_map[k] = EVAL(m[k], env);
}
MalHashMap(new_map);
case _: ast;
}
}
static function EVAL(ast:MalType, env:Map<String,MalType>):MalType {
if (!list_Q(ast)) { return eval_ast(ast, env); }
// apply
var alst = switch (ast) { case MalList(lst): lst; case _: []; }
if (alst.length == 0) { return ast; }
var el = eval_ast(ast, env);
var lst = switch (el) { case MalList(lst): lst; case _: []; }
var a0 = lst[0], args = lst.slice(1);
switch (a0) {
case MalFunc(f,_,_,_,_,_): return f(args);
case _: throw "Call of non-function";
}
}
// PRINT
static function PRINT(exp:MalType):String {
return Printer.pr_str(exp, true);
}
// repl
static function NumOp(op):MalType {
return MalFunc(function(args:Array<MalType>) {
return switch (args) {
case [MalInt(a), MalInt(b)]: MalInt(op(a,b));
case _: throw "Invalid numeric op call";
}
},null,null,null,false,nil);
}
static var repl_env:Map<String,MalType> =
["+" => NumOp(function(a,b) {return a+b;}),
"-" => NumOp(function(a,b) {return a-b;}),
"*" => NumOp(function(a,b) {return a*b;}),
"/" => NumOp(function(a,b) {return Std.int(a/b);})];
static function rep(line:String):String {
return PRINT(EVAL(READ(line), repl_env));
}
public static function main() {
while (true) {
try {
var line = Compat.readline("user> ");
if (line == "") { continue; }
Compat.println(rep(line));
} catch (exc:BlankLine) {
continue;
} catch (exc:haxe.io.Eof) {
Compat.exit(0);
} catch (exc:Dynamic) {
Compat.println(exc);
}
}
}
}