Nim: step2
authordef <dennis@felsin9.de>
Sat, 28 Feb 2015 14:20:37 +0000 (15:20 +0100)
committerdef <dennis@felsin9.de>
Sat, 28 Feb 2015 14:20:37 +0000 (15:20 +0100)
nim/Makefile
nim/printer.nim
nim/step2_eval.nim [new file with mode: 0644]
nim/types.nim

index 5fba42c..8f85496 100644 (file)
@@ -6,7 +6,7 @@ SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
 
 #####################
 
-SRCS = step0_repl.nim step1_read_print.nim
+SRCS = step0_repl.nim step1_read_print.nim step2_eval.nim
 BINS = $(SRCS:%.nim=%)
 
 #####################
index 45c21f1..e3d3aab 100644 (file)
@@ -3,6 +3,7 @@ import strutils, tables, types
 proc pr_str*(m: MalType): string =
   case m.kind
   of Nil:     result = "nil"
+  of Fun:     result = "fun"
   of Symbol:  result = m.symbol
   of Number:  result = $m.number
   of List:    result = "(" & m.list.map(pr_str).join(" ") & ")"
diff --git a/nim/step2_eval.nim b/nim/step2_eval.nim
new file mode 100644 (file)
index 0000000..7418335
--- /dev/null
@@ -0,0 +1,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.symbol):
+      raise newException(ValueError, "'" & ast.symbol & "' not found")
+    result = env[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: 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()
index 866d6db..dfab369 100644 (file)
@@ -1,7 +1,7 @@
 import tables
 
 type
-  MalTypeKind* = enum Nil, Number, Symbol, List, Vector, HashMap
+  MalTypeKind* = enum Nil, Number, Symbol, List, Vector, HashMap, Fun
 
   MalType* = object
     case kind*: MalTypeKind
@@ -11,6 +11,7 @@ type
     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
 
 # Convenience procs
 const nilObj*: MalType = MalType(kind: Nil)
@@ -31,3 +32,5 @@ proc hash_map*(xs: varargs[MalType]): MalType =
   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)