Misc fixes and TODO updates.
[jackhill/mal.git] / ruby / step5_tco.rb
CommitLineData
107d9694
IJ
1require_relative "mal_readline"
2require_relative "types"
3require_relative "reader"
4require_relative "printer"
5require_relative "env"
6require_relative "core"
7d2dad89
JM
7
8# read
9def READ(str)
10 return read_str(str)
11end
12
13# eval
14def eval_ast(ast, env)
15 return case ast
16 when Symbol
17 env.get(ast)
18 when List
19 List.new ast.map{|a| EVAL(a, env)}
20 when Vector
21 Vector.new ast.map{|a| EVAL(a, env)}
3e8a088f
JM
22 when Hash
23 new_hm = {}
24 ast.each{|k,v| new_hm[EVAL(k,env)] = EVAL(v, env)}
25 new_hm
7d2dad89
JM
26 else
27 ast
28 end
29end
30
31def EVAL(ast, env)
32 while true
33
3e8a088f
JM
34 #puts "EVAL: #{_pr_str(ast, true)}"
35
7d2dad89
JM
36 if not ast.is_a? List
37 return eval_ast(ast, env)
38 end
f53183a3
DM
39 if ast.empty?
40 return ast
41 end
7d2dad89
JM
42
43 # apply list
44 a0,a1,a2,a3 = ast
45 case a0
46 when :def!
47 return env.set(a1, EVAL(a2, env))
48 when :"let*"
49 let_env = Env.new(env)
50 a1.each_slice(2) do |a,e|
51 let_env.set(a, EVAL(e, let_env))
52 end
6301e0b6
JM
53 env = let_env
54 ast = a2 # Continue loop (TCO)
7d2dad89
JM
55 when :do
56 eval_ast(ast[1..-2], env)
6301e0b6 57 ast = ast.last # Continue loop (TCO)
7d2dad89
JM
58 when :if
59 cond = EVAL(a1, env)
60 if not cond
61 return nil if a3 == nil
6301e0b6 62 ast = a3 # Continue loop (TCO)
7d2dad89 63 else
6301e0b6 64 ast = a2 # Continue loop (TCO)
7d2dad89
JM
65 end
66 when :"fn*"
67 return Function.new(a2, env, a1) {|*args|
79859c62 68 EVAL(a2, Env.new(env, a1, List.new(args)))
7d2dad89
JM
69 }
70 else
71 el = eval_ast(ast, env)
72 f = el[0]
73 if f.class == Function
74 ast = f.ast
6301e0b6 75 env = f.gen_env(el.drop(1)) # Continue loop (TCO)
7d2dad89
JM
76 else
77 return f[*el.drop(1)]
78 end
79 end
80
81 end
82end
83
84# print
85def PRINT(exp)
86 return _pr_str(exp, true)
87end
88
89# repl
90repl_env = Env.new
91RE = lambda {|str| EVAL(READ(str), repl_env) }
92REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
7d2dad89 93
8cb5cda4
JM
94# core.rb: defined using ruby
95$core_ns.each do |k,v| repl_env.set(k,v) end
7d2dad89 96
8cb5cda4 97# core.mal: defined using the language itself
7d2dad89
JM
98RE["(def! not (fn* (a) (if a false true)))"]
99
86b689f3 100# repl loop
718887c3 101while line = _readline("user> ")
7d2dad89
JM
102 begin
103 puts REP[line]
104 rescue Exception => e
105 puts "Error: #{e}"
e17aef04 106 puts "\t#{e.backtrace[0..100].join("\n\t")}"
7d2dad89
JM
107 end
108end