vb: add seq and string?
[jackhill/mal.git] / ruby / step6_file.rb
CommitLineData
107d9694
IJ
1require_relative "mal_readline"
2require_relative "types"
3require_relative "reader"
4require_relative "printer"
5require_relative "env"
6require_relative "core"
46dbc0d8
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
46dbc0d8
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
46dbc0d8
JM
36 if not ast.is_a? List
37 return eval_ast(ast, env)
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
6301e0b6
JM
50 env = let_env
51 ast = a2 # Continue loop (TCO)
46dbc0d8
JM
52 when :do
53 eval_ast(ast[1..-2], env)
6301e0b6 54 ast = ast.last # Continue loop (TCO)
46dbc0d8
JM
55 when :if
56 cond = EVAL(a1, env)
57 if not cond
58 return nil if a3 == nil
6301e0b6 59 ast = a3 # Continue loop (TCO)
46dbc0d8 60 else
6301e0b6 61 ast = a2 # Continue loop (TCO)
46dbc0d8
JM
62 end
63 when :"fn*"
64 return Function.new(a2, env, a1) {|*args|
79859c62 65 EVAL(a2, Env.new(env, a1, List.new(args)))
46dbc0d8
JM
66 }
67 else
68 el = eval_ast(ast, env)
69 f = el[0]
70 if f.class == Function
71 ast = f.ast
6301e0b6 72 env = f.gen_env(el.drop(1)) # Continue loop (TCO)
46dbc0d8
JM
73 else
74 return f[*el.drop(1)]
75 end
76 end
77
78 end
79end
80
81# print
82def PRINT(exp)
83 return _pr_str(exp, true)
84end
85
86# repl
87repl_env = Env.new
88RE = lambda {|str| EVAL(READ(str), repl_env) }
89REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
46dbc0d8 90
8cb5cda4
JM
91# core.rb: defined using ruby
92$core_ns.each do |k,v| repl_env.set(k,v) end
93repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
86b689f3 94repl_env.set(:"*ARGV*", List.new(ARGV.slice(1,ARGV.length) || []))
46dbc0d8 95
8cb5cda4 96# core.mal: defined using the language itself
46dbc0d8
JM
97RE["(def! not (fn* (a) (if a false true)))"]
98RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
99
46dbc0d8 100if ARGV.size > 0
86b689f3 101 RE["(load-file \"" + ARGV[0] + "\")"]
46dbc0d8
JM
102 exit 0
103end
86b689f3
JM
104
105# repl loop
718887c3 106while line = _readline("user> ")
46dbc0d8
JM
107 begin
108 puts REP[line]
109 rescue Exception => e
110 puts "Error: #{e}"
111 puts "\t#{e.backtrace.join("\n\t")}"
112 end
113end