All: *ARGV* and *host-language*. Misc syncing/fixes.
[jackhill/mal.git] / ruby / step6_file.rb
CommitLineData
718887c3
JM
1$: << File.expand_path(File.dirname(__FILE__))
2require "mal_readline"
46dbc0d8
JM
3require "types"
4require "reader"
5require "printer"
6require "env"
7require "core"
8
9# read
10def READ(str)
11 return read_str(str)
12end
13
14# eval
15def eval_ast(ast, env)
16 return case ast
17 when Symbol
18 env.get(ast)
19 when List
20 List.new ast.map{|a| EVAL(a, env)}
21 when Vector
22 Vector.new ast.map{|a| EVAL(a, env)}
3e8a088f
JM
23 when Hash
24 new_hm = {}
25 ast.each{|k,v| new_hm[EVAL(k,env)] = EVAL(v, env)}
26 new_hm
46dbc0d8
JM
27 else
28 ast
29 end
30end
31
32def EVAL(ast, env)
33 while true
34
3e8a088f
JM
35 #puts "EVAL: #{_pr_str(ast, true)}"
36
46dbc0d8
JM
37 if not ast.is_a? List
38 return eval_ast(ast, env)
39 end
40
41 # apply list
42 a0,a1,a2,a3 = ast
43 case a0
44 when :def!
45 return env.set(a1, EVAL(a2, env))
46 when :"let*"
47 let_env = Env.new(env)
48 a1.each_slice(2) do |a,e|
49 let_env.set(a, EVAL(e, let_env))
50 end
51 return EVAL(a2, let_env)
52 when :do
53 eval_ast(ast[1..-2], env)
54 ast = ast.last
55 when :if
56 cond = EVAL(a1, env)
57 if not cond
58 return nil if a3 == nil
59 ast = a3
60 else
61 ast = a2
62 end
63 when :"fn*"
64 return Function.new(a2, env, a1) {|*args|
65 EVAL(a2, Env.new(env, a1, args))
66 }
67 else
68 el = eval_ast(ast, env)
69 f = el[0]
70 if f.class == Function
71 ast = f.ast
72 env = f.gen_env(el.drop(1))
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