Commit | Line | Data |
---|---|---|
5755c330 DM |
1 | import "./readline" for Readline |
2 | import "./reader" for MalReader | |
3 | import "./printer" for Printer | |
4 | import "./types" for MalSymbol, MalList, MalVector, MalMap | |
5 | ||
6 | class Mal { | |
7 | static read(str) { | |
8 | return MalReader.read_str(str) | |
9 | } | |
10 | ||
11 | static eval_ast(ast, env) { | |
12 | if (ast is MalSymbol) { | |
13 | if (!env.containsKey(ast.value)) Fiber.abort("'%(ast.value)' not found") | |
14 | return env[ast.value] | |
15 | } else if (ast is MalList) { | |
16 | return MalList.new(ast.elements.map { |e| eval(e, env) }.toList) | |
17 | } else if (ast is MalVector) { | |
18 | return MalVector.new(ast.elements.map { |e| eval(e, env) }.toList) | |
19 | } else if (ast is MalMap) { | |
20 | var m = {} | |
21 | for (e in ast.data) { | |
22 | m[e.key] = eval(e.value, env) | |
23 | } | |
24 | return MalMap.new(m) | |
25 | } else { | |
26 | return ast | |
27 | } | |
28 | } | |
29 | ||
30 | static eval(ast, env) { | |
31 | if (!(ast is MalList)) return eval_ast(ast, env) | |
32 | if (ast.isEmpty) return ast | |
33 | var evaled_ast = eval_ast(ast, env) | |
34 | var f = evaled_ast[0] | |
35 | return f.call(evaled_ast[1..-1]) | |
36 | } | |
37 | ||
38 | static print(ast) { | |
39 | return Printer.pr_str(ast) | |
40 | } | |
41 | ||
42 | static rep(str) { | |
43 | return print(eval(read(str), __repl_env)) | |
44 | } | |
45 | ||
46 | static main() { | |
47 | __repl_env = { | |
48 | "+": Fn.new { |a| a[0] + a[1] }, | |
49 | "-": Fn.new { |a| a[0] - a[1] }, | |
50 | "*": Fn.new { |a| a[0] * a[1] }, | |
51 | "/": Fn.new { |a| a[0] / a[1] } | |
52 | } | |
53 | while (true) { | |
54 | var line = Readline.readLine("user> ") | |
55 | if (line == null) break | |
56 | if (line != "") { | |
57 | var fiber = Fiber.new { System.print(rep(line)) } | |
58 | fiber.try() | |
59 | if (fiber.error) System.print("Error: %(fiber.error)") | |
60 | } | |
61 | } | |
62 | System.print() | |
63 | } | |
64 | } | |
65 | ||
66 | Mal.main() |