--- /dev/null
+module env
+
+export Env, set, find, get
+
+type Env
+ outer::Any
+ data::Dict{Symbol,Any}
+end
+
+function Env()
+ Env(nothing, Dict())
+end
+
+function Env(outer)
+ Env(outer, Dict())
+end
+
+function set(env::Env, k::Symbol, v)
+ env.data[k] = v
+end
+
+function find(env::Env, k::Symbol)
+ if haskey(env.data, k)
+ env
+ elseif env.outer != nothing
+ find(env.outer, k)
+ else
+ nothing
+ end
+end
+
+function get(env::Env, k::Symbol)
+ e = find(env, k)
+ if e != nothing
+ e.data[k]
+ else
+ error("'$(string(k))' not found")
+ end
+end
+
+end
function eval_ast(ast, env)
if typeof(ast) == Symbol
env[ast]
- elseif isa(ast, Array)
+ elseif isa(ast, Array) || isa(ast, Tuple)
map((x) -> EVAL(x,env), ast)
else
ast
--- /dev/null
+#!/usr/bin/env julia
+
+import reader
+import printer
+using env
+
+# READ
+function READ(str)
+ reader.read_str(str)
+end
+
+# EVAL
+function eval_ast(ast, env)
+ if typeof(ast) == Symbol
+ get(env,ast)
+ elseif isa(ast, Array) || isa(ast, Tuple)
+ map((x) -> EVAL(x,env), ast)
+ else
+ ast
+ end
+end
+
+function EVAL(ast, env)
+ if !isa(ast, Array)
+ return eval_ast(ast, env)
+ end
+
+ # apply
+ if :def! == ast[1]
+ set(env, ast[2], EVAL(ast[3], env))
+ elseif symbol("let*") == ast[1]
+ let_env = Env(env)
+ for i = 1:2:length(ast[2])
+ set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+ end
+ EVAL(ast[3], let_env)
+ else
+ el = eval_ast(ast, env)
+ f, args = el[1], el[2:end]
+ f(args...)
+ end
+end
+
+# PRINT
+function PRINT(exp)
+ printer.pr_str(exp)
+end
+
+# REPL
+repl_env = Env(nothing,
+ {:+ => +,
+ :- => -,
+ :* => *,
+ :/ => div})
+function REP(str)
+ return PRINT(EVAL(READ(str), repl_env))
+end
+
+while true
+ print("user> ")
+ flush(STDOUT)
+ line = readline(STDIN)
+ if line == ""
+ break
+ end
+ line = chomp(line)
+ try
+ println(REP(line))
+ catch e
+ if isa(e, ErrorException)
+ println("Error: $(e.msg)")
+ else
+ println("Error: $(string(e))")
+ end
+ bt = catch_backtrace()
+ Base.show_backtrace(STDERR, bt)
+ println()
+ end
+end