--- /dev/null
+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()
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
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)
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)