diff options
| author | def <dennis@felsin9.de> | 2015-02-28 16:08:36 +0100 |
|---|---|---|
| committer | def <dennis@felsin9.de> | 2015-02-28 16:08:36 +0100 |
| commit | 7af2994e50b178b31795532c8742da2ec24da9ad (patch) | |
| tree | 6c56ac5cb416e3e5ed478a85d91ee27583e72a18 | |
| parent | c9d2371f7f0a97efe464565fdf8ebc8405eb8780 (diff) | |
| download | mal-7af2994e50b178b31795532c8742da2ec24da9ad.tar.gz mal-7af2994e50b178b31795532c8742da2ec24da9ad.zip | |
Nim: step3
| -rw-r--r-- | nim/env.nim | 20 | ||||
| -rw-r--r-- | nim/step3_env.nim | 73 |
2 files changed, 93 insertions, 0 deletions
diff --git a/nim/env.nim b/nim/env.nim new file mode 100644 index 0000000..616c817 --- /dev/null +++ b/nim/env.nim @@ -0,0 +1,20 @@ +import tables, types + +type Env* = ref object + data: Table[string, MalType] + outer: Env + +proc initEnv*: Env = Env(data: initTable[string, MalType]()) + +proc set*(e: var Env, key: string, value: MalType): MalType {.discardable.} = + e.data[key] = value + value + +proc find(e: Env, key: string): Env = + if e.data.hasKey(key): return e + if e.outer != nil: return e.outer.find(key) + +proc get*(e: Env, key: string): MalType = + let env = e.find(key) + if env == nil: raise newException(ValueError, "'" & key & "' not found") + env.data[key] diff --git a/nim/step3_env.nim b/nim/step3_env.nim new file mode 100644 index 0000000..9da4af4 --- /dev/null +++ b/nim/step3_env.nim @@ -0,0 +1,73 @@ +import rdstdin, tables, sequtils, types, reader, printer, env + +proc read(str: string): MalType = str.read_str + +proc eval(ast: MalType, env: var Env): MalType + +proc eval_ast(ast: MalType, env: var Env): MalType = + case ast.kind + of Symbol: + result = env.get(ast.symbol) + of List: + result = list ast.list.mapIt(MalType, it.eval(env)) + of Vector: + result = vector ast.vector.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: var Env): MalType = + case ast.kind + of List: + let + a0 = ast.list[0] + a1 = ast.list[1] + a2 = ast.list[2] + + case a0.symbol + of "def!": + result = env.set(a1.symbol, a2.eval(env)) + of "let*": + var letEnv: Env + letEnv.deepCopy(env) + case a1.kind + of List: + for i in countup(0, a1.list.high, 2): + letEnv.set(a1.list[i].symbol, a1.list[i+1].eval(letEnv)) + of Vector: + for i in countup(0, a1.vector.high, 2): + letEnv.set(a1.vector[i].symbol, a1.vector[i+1].eval(letEnv)) + else: discard + result = a2.eval(letEnv) + else: + let el = ast.eval_ast(env) + result = el.list[0].fun(el.list[1 .. -1]) + else: + result = 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) + +var repl_env = initEnv() + +repl_env.set("+", wrapNumberFun(`+`)) +repl_env.set("-", wrapNumberFun(`-`)) +repl_env.set("*", wrapNumberFun(`*`)) +repl_env.set("/", wrapNumberFun(`div`)) +#repl_env.set("/", wrapNumberFun(proc(x,y: int): int = int(x.float / y.float))) + +proc rep(str: string): string = + str.read.eval(repl_env).print + +while true: + try: + let line = readLineFromStdin("user> ") + echo line.rep + except: + echo getCurrentExceptionMsg() + echo getCurrentException().getStackTrace() |
