| 1 | require_relative "mal_readline" |
| 2 | require_relative "types" |
| 3 | require_relative "reader" |
| 4 | require_relative "printer" |
| 5 | require_relative "env" |
| 6 | require_relative "core" |
| 7 | |
| 8 | # read |
| 9 | def READ(str) |
| 10 | return read_str(str) |
| 11 | end |
| 12 | |
| 13 | # eval |
| 14 | def 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)} |
| 22 | when Hash |
| 23 | new_hm = {} |
| 24 | ast.each{|k,v| new_hm[EVAL(k,env)] = EVAL(v, env)} |
| 25 | new_hm |
| 26 | else |
| 27 | ast |
| 28 | end |
| 29 | end |
| 30 | |
| 31 | def EVAL(ast, env) |
| 32 | while true |
| 33 | |
| 34 | #puts "EVAL: #{_pr_str(ast, true)}" |
| 35 | |
| 36 | if not ast.is_a? List |
| 37 | return eval_ast(ast, env) |
| 38 | end |
| 39 | if ast.empty? |
| 40 | return ast |
| 41 | end |
| 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 |
| 53 | env = let_env |
| 54 | ast = a2 # Continue loop (TCO) |
| 55 | when :do |
| 56 | eval_ast(ast[1..-2], env) |
| 57 | ast = ast.last # Continue loop (TCO) |
| 58 | when :if |
| 59 | cond = EVAL(a1, env) |
| 60 | if not cond |
| 61 | return nil if a3 == nil |
| 62 | ast = a3 # Continue loop (TCO) |
| 63 | else |
| 64 | ast = a2 # Continue loop (TCO) |
| 65 | end |
| 66 | when :"fn*" |
| 67 | return Function.new(a2, env, a1) {|*args| |
| 68 | EVAL(a2, Env.new(env, a1, List.new(args))) |
| 69 | } |
| 70 | else |
| 71 | el = eval_ast(ast, env) |
| 72 | f = el[0] |
| 73 | if f.class == Function |
| 74 | ast = f.ast |
| 75 | env = f.gen_env(el.drop(1)) # Continue loop (TCO) |
| 76 | else |
| 77 | return f[*el.drop(1)] |
| 78 | end |
| 79 | end |
| 80 | |
| 81 | end |
| 82 | end |
| 83 | |
| 84 | # print |
| 85 | def PRINT(exp) |
| 86 | return _pr_str(exp, true) |
| 87 | end |
| 88 | |
| 89 | # repl |
| 90 | repl_env = Env.new |
| 91 | RE = lambda {|str| EVAL(READ(str), repl_env) } |
| 92 | REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) } |
| 93 | |
| 94 | # core.rb: defined using ruby |
| 95 | $core_ns.each do |k,v| repl_env.set(k,v) end |
| 96 | |
| 97 | # core.mal: defined using the language itself |
| 98 | RE["(def! not (fn* (a) (if a false true)))"] |
| 99 | |
| 100 | # repl loop |
| 101 | while line = _readline("user> ") |
| 102 | begin |
| 103 | puts REP[line] |
| 104 | rescue Exception => e |
| 105 | puts "Error: #{e}" |
| 106 | puts "\t#{e.backtrace[0..100].join("\n\t")}" |
| 107 | end |
| 108 | end |