forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStep4_if_fn_do.hx
114 lines (103 loc) · 3.46 KB
/
Step4_if_fn_do.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import Compat;
import types.Types.MalType;
import types.Types.*;
import reader.*;
import printer.*;
import env.*;
import core.*;
class Step4_if_fn_do {
// READ
static function READ(str:String):MalType {
return Reader.read_str(str);
}
// EVAL
static function eval_ast(ast:MalType, env:Env) {
return switch (ast) {
case MalSymbol(s): env.get(ast);
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:Env):MalType {
if (!list_Q(ast)) { return eval_ast(ast, env); }
// apply
var alst = _list(ast);
if (alst.length == 0) { return ast; }
switch (alst[0]) {
case MalSymbol("def!"):
return env.set(alst[1], EVAL(alst[2], env));
case MalSymbol("let*"):
var let_env = new Env(env);
switch (alst[1]) {
case MalList(l) | MalVector(l):
for (i in 0...l.length) {
if ((i%2) > 0) { continue; }
let_env.set(l[i], EVAL(l[i+1], let_env));
}
case _: throw "Invalid let*";
}
return EVAL(alst[2], let_env);
case MalSymbol("do"):
return last(eval_ast(MalList(alst.slice(1)), env));
case MalSymbol("if"):
var cond = EVAL(alst[1], env);
if (cond != MalFalse && cond != MalNil) {
return EVAL(alst[2], env);
} else if (alst.length > 3) {
return EVAL(alst[3], env);
} else {
return MalNil;
}
case MalSymbol("fn*"):
return MalFunc(function (args) {
return EVAL(alst[2], new Env(env, _list(alst[1]), args));
},null,null,null,false,nil);
case _:
var el = eval_ast(ast, env);
var lst = _list(el);
switch (first(el)) {
case MalFunc(f,_,_,_,_,_): return f(_list(el).slice(1));
case _: throw "Call of non-function";
}
}
}
// PRINT
static function PRINT(exp:MalType):String {
return Printer.pr_str(exp, true);
}
// repl
static var repl_env = new Env(null);
static function rep(line:String):String {
return PRINT(EVAL(READ(line), repl_env));
}
public static function main() {
// core.EXT: defined using Haxe
for (k in Core.ns.keys()) {
repl_env.set(MalSymbol(k), MalFunc(Core.ns[k],null,null,null,false,nil));
}
// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
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);
}
}
}
}