Merge pull request #337 from AndreaCrotti/upgrade-libraries
[jackhill/mal.git] / ruby / step3_env.rb
1 require_relative "mal_readline"
2 require_relative "types"
3 require_relative "reader"
4 require_relative "printer"
5 require_relative "env"
6
7 # read
8 def READ(str)
9 return read_str(str)
10 end
11
12 # eval
13 def eval_ast(ast, env)
14 return case ast
15 when Symbol
16 env.get(ast)
17 when List
18 List.new ast.map{|a| EVAL(a, env)}
19 when Vector
20 Vector.new ast.map{|a| EVAL(a, env)}
21 when Hash
22 new_hm = {}
23 ast.each{|k,v| new_hm[EVAL(k,env)] = EVAL(v, env)}
24 new_hm
25 else
26 ast
27 end
28 end
29
30 def EVAL(ast, env)
31 #puts "EVAL: #{_pr_str(ast, true)}"
32
33 if not ast.is_a? List
34 return eval_ast(ast, env)
35 end
36 if ast.empty?
37 return ast
38 end
39
40 # apply list
41 a0,a1,a2,a3 = ast
42 case a0
43 when :def!
44 return env.set(a1, EVAL(a2, env))
45 when :"let*"
46 let_env = Env.new(env)
47 a1.each_slice(2) do |a,e|
48 let_env.set(a, EVAL(e, let_env))
49 end
50 return EVAL(a2, let_env)
51 else
52 el = eval_ast(ast, env)
53 f = el[0]
54 return f[*el.drop(1)]
55 end
56 end
57
58 # print
59 def PRINT(exp)
60 return _pr_str(exp, true)
61 end
62
63 # repl
64 repl_env = Env.new
65 REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
66
67 repl_env.set(:+, lambda {|a,b| a + b})
68 repl_env.set(:-, lambda {|a,b| a - b})
69 repl_env.set(:*, lambda {|a,b| a * b})
70 repl_env.set(:/, lambda {|a,b| a / b})
71
72 # repl loop
73 while line = _readline("user> ")
74 begin
75 puts REP[line]
76 rescue Exception => e
77 puts "Error: #{e}"
78 puts "\t#{e.backtrace.join("\n\t")}"
79 end
80 end