diff options
| author | def <dennis@felsin9.de> | 2015-03-01 04:38:43 +0100 |
|---|---|---|
| committer | def <dennis@felsin9.de> | 2015-03-01 04:38:43 +0100 |
| commit | 3603af9666161a66c5a846c33a1b2663044c73af (patch) | |
| tree | c2fb5efbac740d2520953a30ec1adc95813aa38a | |
| parent | 5dfcbb6b4dccefd79c7ec5577b215fc50cef46d2 (diff) | |
| download | mal-3603af9666161a66c5a846c33a1b2663044c73af.tar.gz mal-3603af9666161a66c5a846c33a1b2663044c73af.zip | |
Nim: step6
| -rw-r--r-- | nim/core.nim | 11 | ||||
| -rw-r--r-- | nim/env.nim | 6 | ||||
| -rw-r--r-- | nim/printer.nim | 2 | ||||
| -rw-r--r-- | nim/reader.nim | 14 | ||||
| -rw-r--r-- | nim/step2_eval.nim | 6 | ||||
| -rw-r--r-- | nim/step3_env.nim | 8 | ||||
| -rw-r--r-- | nim/step4_if_fn_do.nim | 8 | ||||
| -rw-r--r-- | nim/step5_tco.nim | 8 | ||||
| -rw-r--r-- | nim/step6_file.nim | 122 | ||||
| -rw-r--r-- | nim/types.nim | 35 |
10 files changed, 179 insertions, 41 deletions
diff --git a/nim/core.nim b/nim/core.nim index 5a6904c..c32bc6f 100644 --- a/nim/core.nim +++ b/nim/core.nim @@ -1,4 +1,4 @@ -import strutils, types, printer +import strutils, types, printer, reader # String functions proc pr_str(xs: varargs[MalType]): MalType = @@ -16,6 +16,12 @@ proc println(xs: varargs[MalType]): MalType = echo line.replace("\\n", "\n") result = nilObj +proc read_str(xs: varargs[MalType]): MalType = + read_str(xs[0].str) + +proc slurp(xs: varargs[MalType]): MalType = + str readFile(xs[0].str) + template wrapNumberFun(op: expr): expr = fun proc(xs: varargs[MalType]): MalType = number op(xs[0].number, xs[1].number) @@ -48,4 +54,7 @@ let ns* = { "str": fun do_str, "prn": fun prn, "println": fun println, + + "read-string": fun read_str, + "slurp": fun slurp, } diff --git a/nim/env.nim b/nim/env.nim index 55e2a09..bb4ad41 100644 --- a/nim/env.nim +++ b/nim/env.nim @@ -5,11 +5,11 @@ proc initEnv*(outer: Env = nil, binds, exprs: MalType = nilObj): Env = if binds.kind in {List, Vector}: for i, e in binds.list: - if e.symbol == "&": - result.data[binds.list[i+1].symbol] = list(exprs.list[i .. exprs.list.high]) + if e.str == "&": + result.data[binds.list[i+1].str] = list(exprs.list[i .. exprs.list.high]) break else: - result.data[e.symbol] = exprs.list[i] + result.data[e.str] = exprs.list[i] proc set*(e: var Env, key: string, value: MalType): MalType {.discardable.} = e.data[key] = value diff --git a/nim/printer.nim b/nim/printer.nim index 7bdf78c..eb26671 100644 --- a/nim/printer.nim +++ b/nim/printer.nim @@ -7,7 +7,7 @@ proc pr_str*(m: MalType, pr = true): string = of False: result = "false" of Fun: result = "#<function>" of MalFun: result = "#<malfun>" - of Symbol: result = m.symbol + of Symbol: result = m.str of String: if m.str.len > 0 and m.str[0] == '\xff': result = ":" & m.str[1 .. m.str.high] diff --git a/nim/reader.nim b/nim/reader.nim index fef213a..856a6a6 100644 --- a/nim/reader.nim +++ b/nim/reader.nim @@ -4,9 +4,12 @@ var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)""" intRE = re"-?[0-9]+$" -type Reader = object - tokens: seq[string] - position: int +type + Blank* = object of Exception + + Reader = object + tokens: seq[string] + position: int proc next(r: var Reader): string = if r.position >= r.tokens.len: @@ -22,7 +25,8 @@ proc peek(r: Reader): string = proc tokenize(str: string): seq[string] = result = @[] for match in str.findIter(tokenRE): - result.add match.captures[0] + if match.captures[0][0] != ';': + result.add match.captures[0] proc read_form(r: var Reader): MalType @@ -99,4 +103,6 @@ proc read_form(r: var Reader): MalType = proc read_str*(str: string): MalType = var r = Reader(tokens: str.tokenize) + if r.tokens.len == 0: + raise newException(Blank, "Blank line") r.read_form diff --git a/nim/step2_eval.nim b/nim/step2_eval.nim index 566003c..075b4ac 100644 --- a/nim/step2_eval.nim +++ b/nim/step2_eval.nim @@ -7,9 +7,9 @@ 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.symbol): - raise newException(ValueError, "'" & ast.symbol & "' not found") - result = env[ast.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: diff --git a/nim/step3_env.nim b/nim/step3_env.nim index e118872..98438fe 100644 --- a/nim/step3_env.nim +++ b/nim/step3_env.nim @@ -7,7 +7,7 @@ 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) + result = env.get(ast.str) of List: result = list ast.list.mapIt(MalType, it.eval(env)) of Vector: @@ -27,16 +27,16 @@ proc eval(ast: MalType, env: var Env): MalType = a1 = ast.list[1] a2 = ast.list[2] - case a0.symbol + case a0.str of "def!": - result = env.set(a1.symbol, a2.eval(env)) + result = env.set(a1.str, a2.eval(env)) of "let*": var letEnv: Env letEnv.deepCopy(env) case a1.kind of List, Vector: for i in countup(0, a1.list.high, 2): - letEnv.set(a1.list[i].symbol, a1.list[i+1].eval(letEnv)) + letEnv.set(a1.list[i].str, a1.list[i+1].eval(letEnv)) else: discard result = a2.eval(letEnv) else: diff --git a/nim/step4_if_fn_do.nim b/nim/step4_if_fn_do.nim index b235733..a4a8dd1 100644 --- a/nim/step4_if_fn_do.nim +++ b/nim/step4_if_fn_do.nim @@ -7,7 +7,7 @@ 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) + result = env.get(ast.str) of List: result = list ast.list.mapIt(MalType, it.eval(env)) of Vector: @@ -25,12 +25,12 @@ proc eval(ast: MalType, env: var Env): MalType = let a0 = ast.list[0] case a0.kind of Symbol: - case a0.symbol + case a0.str of "def!": let a1 = ast.list[1] a2 = ast.list[2] - result = env.set(a1.symbol, a2.eval(env)) + result = env.set(a1.str, a2.eval(env)) of "let*": let @@ -42,7 +42,7 @@ proc eval(ast: MalType, env: var Env): MalType = case a1.kind of List, Vector: for i in countup(0, a1.list.high, 2): - letEnv.set(a1.list[i].symbol, a1.list[i+1].eval(letEnv)) + letEnv.set(a1.list[i].str, a1.list[i+1].eval(letEnv)) else: discard result = a2.eval(letEnv) diff --git a/nim/step5_tco.nim b/nim/step5_tco.nim index f7140e7..3c91706 100644 --- a/nim/step5_tco.nim +++ b/nim/step5_tco.nim @@ -7,7 +7,7 @@ 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) + result = env.get(ast.str) of List: result = list ast.list.mapIt(MalType, it.eval(env)) of Vector: @@ -38,12 +38,12 @@ proc eval(ast: MalType, env: var Env): MalType = let a0 = ast.list[0] case a0.kind of Symbol: - case a0.symbol + case a0.str of "def!": let a1 = ast.list[1] a2 = ast.list[2] - return env.set(a1.symbol, a2.eval(env)) + return env.set(a1.str, a2.eval(env)) of "let*": let @@ -52,7 +52,7 @@ proc eval(ast: MalType, env: var Env): MalType = 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)) + env.set(a1.list[i].str, a1.list[i+1].eval(env)) else: discard # Continue loop (TCO) diff --git a/nim/step6_file.nim b/nim/step6_file.nim new file mode 100644 index 0000000..53269aa --- /dev/null +++ b/nim/step6_file.nim @@ -0,0 +1,122 @@ +import rdstdin, tables, sequtils, os, 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.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: 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.str + of "def!": + let + a1 = ast.list[1] + a2 = ast.list[2] + return env.set(a1.str, 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].str, 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) +repl_env.set("eval", fun(proc(xs: varargs[MalType]): MalType = eval(xs[0], repl_env))) +var ps = commandLineParams() +repl_env.set("*ARGV*", list((if paramCount() > 1: ps[1..ps.high] else: @[]).map(str))) + + +# core.nim: defined using nim +proc rep(str: string): string {.discardable.} = + str.read.eval(repl_env).print + +# core.mal: defined using mal itself +rep "(def! not (fn* (a) (if a false true)))" +rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" + +if paramCount() >= 1: + rep "(load-file \"" & paramStr(1) & "\")" + quit() + +while true: + try: + let line = readLineFromStdin("user> ") + echo line.rep + except Blank: discard + except: + echo getCurrentExceptionMsg() + echo getCurrentException().getStackTrace() diff --git a/nim/types.nim b/nim/types.nim index f677f06..278ae1b 100644 --- a/nim/types.nim +++ b/nim/types.nim @@ -13,13 +13,12 @@ type MalType* = object case kind*: MalTypeKind of Nil, True, False: nil - of Number: number*: int - of Symbol: symbol*: string - of String: str*: string - 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 + of Number: number*: int + of String, Symbol: str*: string + 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] @@ -32,9 +31,9 @@ const falseObj* = MalType(kind: False) proc number*(x: int): MalType = MalType(kind: Number, number: x) -proc symbol*(x: string): MalType = MalType(kind: Symbol, symbol: x) +proc symbol*(x: string): MalType = MalType(kind: Symbol, str: x) -proc str*(x: string): MalType = MalType(kind: String, str: x) +proc str*(x: string): MalType {.procvar.} = MalType(kind: String, str: x) proc keyword*(x: string): MalType = MalType(kind: String, str: "\xff" & x) @@ -49,7 +48,10 @@ proc vector*(xs: varargs[MalType]): MalType {.procvar.} = proc hash_map*(xs: varargs[MalType]): MalType {.procvar.} = result = MalType(kind: HashMap, hash_map: newTable[string, MalType]()) for i in countup(0, xs.high, 2): - result.hash_map[xs[i].symbol] = xs[i+1] + let s = case xs[i].kind + of String: "\"" & xs[i].str & "\"" + else: xs[i].str + result.hash_map[s] = xs[i+1] proc fun*(x: proc(xs: varargs[MalType]): MalType): MalType = MalType(kind: Fun, fun: x) @@ -81,13 +83,12 @@ proc `==`*(x, y: MalType): bool = if x.kind != y.kind: return false result = case x.kind of Nil, True, False: true - of Number: x.number == y.number - of Symbol: x.symbol == y.symbol - of String: x.str == y.str - 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 + of Number: x.number == y.number + of Symbol, String: x.str == y.str + 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] |
