diff options
| author | def <dennis@felsin9.de> | 2015-03-01 03:55:05 +0100 |
|---|---|---|
| committer | def <dennis@felsin9.de> | 2015-03-01 03:55:05 +0100 |
| commit | 5dfcbb6b4dccefd79c7ec5577b215fc50cef46d2 (patch) | |
| tree | 534661fa2ad37dc74f812024fca0e4f437368bdd | |
| parent | 819bd786cb21c393d4f94e682758addc253e1a20 (diff) | |
| download | mal-5dfcbb6b4dccefd79c7ec5577b215fc50cef46d2.tar.gz mal-5dfcbb6b4dccefd79c7ec5577b215fc50cef46d2.zip | |
Nim: step5
| -rw-r--r-- | nim/env.nim | 4 | ||||
| -rw-r--r-- | nim/printer.nim | 1 | ||||
| -rw-r--r-- | nim/step5_tco.nim | 112 | ||||
| -rw-r--r-- | nim/types.nim | 19 |
4 files changed, 131 insertions, 5 deletions
diff --git a/nim/env.nim b/nim/env.nim index b5c5a37..55e2a09 100644 --- a/nim/env.nim +++ b/nim/env.nim @@ -1,9 +1,5 @@ import tables, types -type Env* = ref object - data: Table[string, MalType] - outer: Env - proc initEnv*(outer: Env = nil, binds, exprs: MalType = nilObj): Env = result = Env(data: initTable[string, MalType](), outer: outer) diff --git a/nim/printer.nim b/nim/printer.nim index aa4507f..7bdf78c 100644 --- a/nim/printer.nim +++ b/nim/printer.nim @@ -6,6 +6,7 @@ proc pr_str*(m: MalType, pr = true): string = of True: result = "true" of False: result = "false" of Fun: result = "#<function>" + of MalFun: result = "#<malfun>" of Symbol: result = m.symbol of String: if m.str.len > 0 and m.str[0] == '\xff': diff --git a/nim/step5_tco.nim b/nim/step5_tco.nim new file mode 100644 index 0000000..f7140e7 --- /dev/null +++ b/nim/step5_tco.nim @@ -0,0 +1,112 @@ +import rdstdin, tables, sequtils, types, reader, printer, env, core + +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.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: var Env): MalType = + template defaultApply = + let el = ast.eval_ast(env) + let f = el.list[0] + case f.kind + of MalFun: + ast = f.malfun.ast + env = initEnv(f.malfun.env, f.malfun.params, list(el.list[1 .. -1])) + else: + return f.fun(el.list[1 .. -1]) + + var ast = ast + while true: + if ast.kind != List: + return ast.eval_ast(env) + + let a0 = ast.list[0] + case a0.kind + of Symbol: + case a0.symbol + of "def!": + let + a1 = ast.list[1] + a2 = ast.list[2] + return env.set(a1.symbol, a2.eval(env)) + + of "let*": + let + a1 = ast.list[1] + a2 = ast.list[2] + case a1.kind + of List, Vector: + for i in countup(0, a1.list.high, 2): + env.set(a1.list[i].symbol, a1.list[i+1].eval(env)) + else: discard + # Continue loop (TCO) + + of "do": + let last = ast.list.high + let el = (list ast.list[1 .. <last]).eval_ast(env) + ast = ast.list[last].eval(env) + # Continue loop (TCO) + + of "if": + let + a1 = ast.list[1] + a2 = ast.list[2] + cond = a1.eval(env) + + if cond.kind in {Nil, False}: + if ast.list.len > 3: ast = ast.list[3] + else: ast = nilObj + else: ast = a2 + + of "fn*": + let + a1 = ast.list[1] + a2 = ast.list[2] + var env2 = env + let fn = proc(a: varargs[MalType]): MalType = + var newEnv = initEnv(env2, a1, list(a)) + a2.eval(newEnv) + return malfun(fn, a2, a1, env2) + + else: + defaultApply() + + else: + defaultApply() + +proc print(exp: MalType): string = exp.pr_str + +var repl_env = initEnv() + +for k, v in ns.items: + repl_env.set(k, v) + +# core.nim: defined using nim +proc rep(str: string): string = + str.read.eval(repl_env).print + +# core.mal: defined using mal itself +discard rep "(def! not (fn* (a) (if a false true)))" + +while true: + try: + let line = readLineFromStdin("user> ") + echo line.rep + except: + echo getCurrentExceptionMsg() + echo getCurrentException().getStackTrace() diff --git a/nim/types.nim b/nim/types.nim index 557a314..f677f06 100644 --- a/nim/types.nim +++ b/nim/types.nim @@ -2,7 +2,13 @@ import tables, strutils type MalTypeKind* = enum Nil, True, False, Number, Symbol, String, - List, Vector, HashMap, Fun + List, Vector, HashMap, Fun, MalFun + + MalFunType* = ref object + fn*: proc(a: varargs[MalType]): MalType + ast*: MalType + params*: MalType + env*: Env MalType* = object case kind*: MalTypeKind @@ -13,6 +19,11 @@ type of List, Vector: list*: seq[MalType] of HashMap: hash_map*: TableRef[string, MalType] of Fun: fun*: proc(xs: varargs[MalType]): MalType + of MalFun: malfun*: MalFunType + + Env* = ref object + data*: Table[string, MalType] + outer*: Env # Convenience procs const nilObj* = MalType(kind: Nil) @@ -42,6 +53,11 @@ proc hash_map*(xs: varargs[MalType]): MalType {.procvar.} = proc fun*(x: proc(xs: varargs[MalType]): MalType): MalType = MalType(kind: Fun, fun: x) +proc malfun*(fn: auto, ast, params: MalType, + env: Env): MalType = + MalType(kind: MalFun, + malfun: MalFunType(fn: fn, ast: ast, params: params, env: env)) + proc boolObj(b: bool): MalType = if b: trueObj else: falseObj @@ -71,6 +87,7 @@ proc `==`*(x, y: MalType): bool = of List, Vector: x.list == y.list of HashMap: x.hash_map == y.hash_map of Fun: x.fun == y.fun + of MalFun: x.malfun == y.malfun proc equal*(xs: varargs[MalType]): MalType {.procvar.} = boolObj xs[0] == xs[1] |
