7af2994e |
1 | import rdstdin, tables, sequtils, types, reader, printer, env |
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) |
7af2994e |
11 | of List: |
12 | result = list ast.list.mapIt(MalType, it.eval(env)) |
13 | of Vector: |
819bd786 |
14 | result = vector ast.list.mapIt(MalType, it.eval(env)) |
7af2994e |
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: |
920963d6 |
25 | if ast.list.len == 0: return ast |
7af2994e |
26 | let |
27 | a0 = ast.list[0] |
28 | a1 = ast.list[1] |
29 | a2 = ast.list[2] |
30 | |
3603af96 |
31 | case a0.str |
7af2994e |
32 | of "def!": |
3603af96 |
33 | result = env.set(a1.str, a2.eval(env)) |
7af2994e |
34 | of "let*": |
35 | var letEnv: Env |
36 | letEnv.deepCopy(env) |
37 | case a1.kind |
819bd786 |
38 | of List, Vector: |
7af2994e |
39 | for i in countup(0, a1.list.high, 2): |
3603af96 |
40 | letEnv.set(a1.list[i].str, a1.list[i+1].eval(letEnv)) |
7af2994e |
41 | else: discard |
42 | result = a2.eval(letEnv) |
43 | else: |
44 | let el = ast.eval_ast(env) |
3f429bf4 |
45 | result = el.list[0].fun(el.list[1 .. ^1]) |
7af2994e |
46 | else: |
47 | result = ast.eval_ast(env) |
48 | |
49 | proc print(exp: MalType): string = exp.pr_str |
50 | |
51 | template wrapNumberFun(op: expr): expr = |
52 | fun proc(xs: varargs[MalType]): MalType = number op(xs[0].number, xs[1].number) |
53 | |
54 | var repl_env = initEnv() |
55 | |
56 | repl_env.set("+", wrapNumberFun(`+`)) |
57 | repl_env.set("-", wrapNumberFun(`-`)) |
58 | repl_env.set("*", wrapNumberFun(`*`)) |
59 | repl_env.set("/", wrapNumberFun(`div`)) |
60 | #repl_env.set("/", wrapNumberFun(proc(x,y: int): int = int(x.float / y.float))) |
61 | |
62 | proc rep(str: string): string = |
63 | str.read.eval(repl_env).print |
64 | |
65 | while true: |
66 | try: |
67 | let line = readLineFromStdin("user> ") |
68 | echo line.rep |
69 | except: |
70 | echo getCurrentExceptionMsg() |
71 | echo getCurrentException().getStackTrace() |