From 819bd786cb21c393d4f94e682758addc253e1a20 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 28 Feb 2015 19:52:01 +0100 Subject: Nim: step4 --- nim/core.nim | 51 ++++++++++++++++++++++++ nim/env.nim | 11 +++++- nim/printer.nim | 19 ++++++--- nim/reader.nim | 5 +++ nim/step2_eval.nim | 2 +- nim/step3_env.nim | 7 +--- nim/step4_if_fn_do.nim | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ nim/types.nim | 70 ++++++++++++++++++++++++++------- 8 files changed, 241 insertions(+), 28 deletions(-) create mode 100644 nim/core.nim create mode 100644 nim/step4_if_fn_do.nim diff --git a/nim/core.nim b/nim/core.nim new file mode 100644 index 0000000..5a6904c --- /dev/null +++ b/nim/core.nim @@ -0,0 +1,51 @@ +import strutils, types, printer + +# String functions +proc pr_str(xs: varargs[MalType]): MalType = + str(xs.map(proc(x: MalType): string = x.pr_str(true)).join(" ").replace("\\", "\\\\")) + +proc do_str(xs: varargs[MalType]): MalType = + str(xs.map(proc(x: MalType): string = x.pr_str(false)).join.replace("\\", "\\\\")) + +proc prn(xs: varargs[MalType]): MalType = + echo xs.map(proc(x: MalType): string = x.pr_str(true)).join(" ") + result = nilObj + +proc println(xs: varargs[MalType]): MalType = + let line = xs.map(proc(x: MalType): string = x.pr_str(false)).join(" ") + echo line.replace("\\n", "\n") + result = nilObj + +template wrapNumberFun(op: expr): expr = + fun proc(xs: varargs[MalType]): MalType = number op(xs[0].number, xs[1].number) + +template wrapBoolFun(op: expr): expr = + fun proc(xs: varargs[MalType]): MalType = + if op(xs[0].number, xs[1].number): trueObj else: falseObj + +let ns* = { + "+": wrapNumberFun(`+`), + "-": wrapNumberFun(`-`), + "*": wrapNumberFun(`*`), + "/": wrapNumberFun(`div`), + + "<": wrapBoolFun(`<`), + "<=": wrapBoolFun(`<=`), + ">": wrapBoolFun(`>`), + ">=": wrapBoolFun(`>=`), + + "list": fun list, + "list?": fun list_q, + "vector": fun vector, + "vector?": fun vector_q, + "hash_map": fun hash_map, + "hash_map?": fun hash_map_q, + "empty?": fun empty_q, + "count": fun count, + "=": fun equal, + + "pr-str": fun pr_str, + "str": fun do_str, + "prn": fun prn, + "println": fun println, +} diff --git a/nim/env.nim b/nim/env.nim index 616c817..b5c5a37 100644 --- a/nim/env.nim +++ b/nim/env.nim @@ -4,7 +4,16 @@ type Env* = ref object data: Table[string, MalType] outer: Env -proc initEnv*: Env = Env(data: initTable[string, MalType]()) +proc initEnv*(outer: Env = nil, binds, exprs: MalType = nilObj): Env = + result = Env(data: initTable[string, MalType](), outer: outer) + + 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]) + break + else: + result.data[e.symbol] = 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 e3d3aab..aa4507f 100644 --- a/nim/printer.nim +++ b/nim/printer.nim @@ -1,16 +1,23 @@ -import strutils, tables, types +import strutils, sequtils, tables, types -proc pr_str*(m: MalType): string = +proc pr_str*(m: MalType, pr = true): string = case m.kind of Nil: result = "nil" - of Fun: result = "fun" + of True: result = "true" + of False: result = "false" + of Fun: result = "#" of Symbol: result = m.symbol + of String: + if m.str.len > 0 and m.str[0] == '\xff': + result = ":" & m.str[1 .. m.str.high] + elif pr: result = "\"" & m.str.replace("\"", "\\\"") & "\"" + else: result = m.str of Number: result = $m.number - of List: result = "(" & m.list.map(pr_str).join(" ") & ")" - of Vector: result = "[" & m.vector.map(pr_str).join(" ") & "]" + of List: result = "(" & m.list.mapIt(string, it.pr_str(pr)).join(" ") & ")" + of Vector: result = "[" & m.list.mapIt(string, it.pr_str(pr)).join(" ") & "]" of HashMap: result = "{" for key, val in m.hash_map.pairs: if result.len > 1: result.add " " - result.add key & " " & val.pr_str + result.add key & " " & val.pr_str(pr) result.add "}" diff --git a/nim/reader.nim b/nim/reader.nim index c8f9096..fef213a 100644 --- a/nim/reader.nim +++ b/nim/reader.nim @@ -50,6 +50,11 @@ proc read_hash_map(r: var Reader): MalType = proc read_atom(r: var Reader): MalType = let t = r.next if t.match(intRE): number t.parseInt + elif t[0] == '"': str t[1 .. 3: result = ast.list[3].eval(env) + else: result = nilObj + else: result = a2.eval(env) + + of "fn*": + let + a1 = ast.list[1] + a2 = ast.list[2] + var env2 = env + result = fun(proc(a: varargs[MalType]): MalType = + var newEnv = initEnv(env2, a1, list(a)) + a2.eval(newEnv)) + + else: + let el = ast.eval_ast(env) + result = el.list[0].fun(el.list[1 .. -1]) + + 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 + +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 dfab369..557a314 100644 --- a/nim/types.nim +++ b/nim/types.nim @@ -1,36 +1,76 @@ -import tables +import tables, strutils type - MalTypeKind* = enum Nil, Number, Symbol, List, Vector, HashMap, Fun + MalTypeKind* = enum Nil, True, False, Number, Symbol, String, + List, Vector, HashMap, Fun MalType* = object case kind*: MalTypeKind - of Nil: nil - of Number: number*: int - of Symbol: symbol*: string - of List: list*: seq[MalType] - of Vector: vector*: seq[MalType] - of HashMap: hash_map*: TableRef[string, MalType] - of Fun: fun*: proc(xs: varargs[MalType]): MalType + 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 # Convenience procs -const nilObj*: MalType = MalType(kind: Nil) +const nilObj* = MalType(kind: Nil) +const trueObj* = MalType(kind: True) +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 list*(xs: varargs[MalType]): MalType = +proc str*(x: string): MalType = MalType(kind: String, str: x) + +proc keyword*(x: string): MalType = MalType(kind: String, str: "\xff" & x) + +proc list*(xs: varargs[MalType]): MalType {.procvar.} = result = MalType(kind: List, list: @[]) for x in xs: result.list.add x -proc vector*(xs: varargs[MalType]): MalType = - result = MalType(kind: Vector, vector: @[]) - for x in xs: result.vector.add x +proc vector*(xs: varargs[MalType]): MalType {.procvar.} = + result = MalType(kind: Vector, list: @[]) + for x in xs: result.list.add x -proc hash_map*(xs: varargs[MalType]): MalType = +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] proc fun*(x: proc(xs: varargs[MalType]): MalType): MalType = MalType(kind: Fun, fun: x) + +proc boolObj(b: bool): MalType = + if b: trueObj else: falseObj + +proc list_q*(xs: varargs[MalType]): MalType {.procvar.} = + boolObj xs[0].kind == List + +proc vector_q*(xs: varargs[MalType]): MalType {.procvar.} = + boolObj xs[0].kind == Vector + +proc hash_map_q*(xs: varargs[MalType]): MalType {.procvar.} = + boolObj xs[0].kind == HashMap + +proc empty_q*(xs: varargs[MalType]): MalType {.procvar.} = + boolObj xs[0].list.len == 0 + +proc count*(xs: varargs[MalType]): MalType {.procvar.} = + number if xs[0].kind == Nil: 0 else: xs[0].list.len + +proc `==`*(x, y: MalType): bool = + if not (x.kind in {List, Vector} and y.kind in {List, Vector}): + 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 + +proc equal*(xs: varargs[MalType]): MalType {.procvar.} = + boolObj xs[0] == xs[1] -- cgit v1.2.3