Merge pull request #217 from dubek/lua-interop
[jackhill/mal.git] / nim / step2_eval.nim
1 import rdstdin, tables, sequtils, types, reader, printer
2
3 proc read(str: string): MalType = str.read_str
4
5 proc eval(ast: MalType, env: Table[string, MalType]): MalType
6
7 proc eval_ast(ast: MalType, env: Table[string, MalType]): MalType =
8 case ast.kind
9 of Symbol:
10 if not env.hasKey(ast.str):
11 raise newException(ValueError, "'" & ast.str & "' not found")
12 result = env[ast.str]
13 of List:
14 result = list ast.list.mapIt(MalType, it.eval(env))
15 of Vector:
16 result = vector ast.list.mapIt(MalType, it.eval(env))
17 of HashMap:
18 result = hash_map()
19 for k, v in ast.hash_map.pairs:
20 result.hash_map[k] = v.eval(env)
21 else:
22 result = ast
23
24 proc eval(ast: MalType, env: Table[string, MalType]): MalType =
25 case ast.kind
26 of List:
27 if ast.list.len == 0: return ast
28 let el = ast.eval_ast(env)
29 el.list[0].fun(el.list[1 .. ^1])
30 else:
31 ast.eval_ast(env)
32
33 proc print(exp: MalType): string = exp.pr_str
34
35 template wrapNumberFun(op: expr): expr =
36 fun proc(xs: varargs[MalType]): MalType = number op(xs[0].number, xs[1].number)
37
38 let repl_env = toTable({
39 "+": wrapNumberFun `+`,
40 "-": wrapNumberFun `-`,
41 "*": wrapNumberFun `*`,
42 "/": wrapNumberFun `div`,
43 })
44
45 proc rep(str: string): string =
46 str.read.eval(repl_env).print
47
48 while true:
49 try:
50 let line = readLineFromStdin("user> ")
51 echo line.rep
52 except:
53 echo getCurrentExceptionMsg()