819bd786 |
1 | import rdstdin, tables, sequtils, types, reader, printer, env, core |
2 | |
3 | proc read(str: string): MalType = str.read_str |
4 | |
5 | proc eval(ast: MalType, env: var Env): MalType |
6 | |
7 | proc eval_ast(ast: MalType, env: var Env): MalType = |
8 | case ast.kind |
9 | of Symbol: |
3603af96 |
10 | result = env.get(ast.str) |
819bd786 |
11 | of List: |
12 | result = list ast.list.mapIt(MalType, it.eval(env)) |
13 | of Vector: |
14 | result = vector ast.list.mapIt(MalType, it.eval(env)) |
15 | of HashMap: |
16 | result = hash_map() |
17 | for k, v in ast.hash_map.pairs: |
18 | result.hash_map[k] = v.eval(env) |
19 | else: |
20 | result = ast |
21 | |
22 | proc eval(ast: MalType, env: var Env): MalType = |
23 | case ast.kind |
24 | of List: |
25 | let a0 = ast.list[0] |
26 | case a0.kind |
27 | of Symbol: |
3603af96 |
28 | case a0.str |
819bd786 |
29 | of "def!": |
30 | let |
31 | a1 = ast.list[1] |
32 | a2 = ast.list[2] |
3603af96 |
33 | result = env.set(a1.str, a2.eval(env)) |
819bd786 |
34 | |
35 | of "let*": |
36 | let |
37 | a1 = ast.list[1] |
38 | a2 = ast.list[2] |
39 | var letEnv: Env |
40 | letEnv.deepCopy(env) |
41 | |
42 | case a1.kind |
43 | of List, Vector: |
44 | for i in countup(0, a1.list.high, 2): |
3603af96 |
45 | letEnv.set(a1.list[i].str, a1.list[i+1].eval(letEnv)) |
819bd786 |
46 | else: discard |
47 | result = a2.eval(letEnv) |
48 | |
49 | of "do": |
50 | let el = (list ast.list[1 .. -1]).eval_ast(env) |
51 | result = el.list[el.list.high] |
52 | |
53 | of "if": |
54 | let |
55 | a1 = ast.list[1] |
56 | a2 = ast.list[2] |
57 | cond = a1.eval(env) |
58 | |
59 | if cond.kind in {Nil, False}: |
60 | if ast.list.len > 3: result = ast.list[3].eval(env) |
61 | else: result = nilObj |
62 | else: result = a2.eval(env) |
63 | |
64 | of "fn*": |
65 | let |
66 | a1 = ast.list[1] |
67 | a2 = ast.list[2] |
68 | var env2 = env |
69 | result = fun(proc(a: varargs[MalType]): MalType = |
70 | var newEnv = initEnv(env2, a1, list(a)) |
71 | a2.eval(newEnv)) |
72 | |
73 | else: |
74 | let el = ast.eval_ast(env) |
75 | result = el.list[0].fun(el.list[1 .. -1]) |
76 | |
77 | else: |
78 | let el = ast.eval_ast(env) |
79 | result = el.list[0].fun(el.list[1 .. -1]) |
80 | |
81 | else: |
82 | result = ast.eval_ast(env) |
83 | |
84 | proc print(exp: MalType): string = exp.pr_str |
85 | |
86 | var repl_env = initEnv() |
87 | |
88 | for k, v in ns.items: |
89 | repl_env.set(k, v) |
90 | |
91 | # core.nim: defined using nim |
92 | proc rep(str: string): string = |
93 | str.read.eval(repl_env).print |
94 | |
95 | # core.mal: defined using mal itself |
96 | discard rep "(def! not (fn* (a) (if a false true)))" |
97 | |
98 | while true: |
99 | try: |
100 | let line = readLineFromStdin("user> ") |
101 | echo line.rep |
102 | except: |
103 | echo getCurrentExceptionMsg() |
104 | echo getCurrentException().getStackTrace() |