aboutsummaryrefslogtreecommitdiff
path: root/nim/step2_eval.nim
blob: 075b4acedf5712d2eba0e74ef354ad941ff45a60 (plain)
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
import rdstdin, tables, sequtils, types, reader, printer

proc read(str: string): MalType = str.read_str

proc eval(ast: MalType, env: Table[string, MalType]): MalType

proc eval_ast(ast: MalType, env: Table[string, MalType]): MalType =
  case ast.kind
  of Symbol:
    if not env.hasKey(ast.str):
      raise newException(ValueError, "'" & ast.str & "' not found")
    result = env[ast.str]
  of List:
    result = list ast.list.mapIt(MalType, it.eval(env))
  of Vector:
    result = vector ast.list.mapIt(MalType, it.eval(env))
  of HashMap:
    result = hash_map()
    for k, v in ast.hash_map.pairs:
      result.hash_map[k] = v.eval(env)
  else:
    result = ast

proc eval(ast: MalType, env: Table[string, MalType]): MalType =
  case ast.kind
  of List:
    let el = ast.eval_ast(env)
    el.list[0].fun(el.list[1 .. -1])
  else:
    ast.eval_ast(env)

proc print(exp: MalType): string = exp.pr_str

template wrapNumberFun(op: expr): expr =
  fun proc(xs: varargs[MalType]): MalType = number op(xs[0].number, xs[1].number)

let repl_env = toTable({
  "+": wrapNumberFun `+`,
  "-": wrapNumberFun `-`,
  "*": wrapNumberFun `*`,
  "/": wrapNumberFun `div`,
})

proc rep(str: string): string =
  str.read.eval(repl_env).print

while true:
  try:
    let line = readLineFromStdin("user> ")
    echo line.rep
  except:
    echo getCurrentExceptionMsg()