1 #! /usr/bin/env crystal run
10 # Employed downcase names because Crystal prohibits uppercase names for methods
13 raise Mal::EvalException.new msg
17 ->(args : Array(Mal::Type)) {
18 x, y = args[0].unwrap, args[1].unwrap
19 eval_error "invalid arguments" unless x.is_a?(Int64) && y.is_a?(Int64)
20 Mal::Type.new func.call(x, y)
24 REPL_ENV = Mal::Env.new nil
25 REPL_ENV.set("+", Mal::Type.new num_func(->(x : Int64, y : Int64) { x + y }))
26 REPL_ENV.set("-", Mal::Type.new num_func(->(x : Int64, y : Int64) { x - y }))
27 REPL_ENV.set("*", Mal::Type.new num_func(->(x : Int64, y : Int64) { x * y }))
28 REPL_ENV.set("/", Mal::Type.new num_func(->(x : Int64, y : Int64) { x / y }))
34 return a.map { |n| eval(n, env) } if a.is_a? Array
36 Mal::Type.new case ast = a.unwrap
38 if e = env.get(ast.str)
41 eval_error "'#{ast.str}' not found"
44 ast.each_with_object(Mal::List.new) { |n, l| l << eval(n, env) }
46 ast.each_with_object(Mal::Vector.new) { |n, l| l << eval(n, env) }
48 new_map = Mal::HashMap.new
49 ast.each { |k, v| new_map[k] = eval(v, env) }
63 return eval_ast(t, env) unless ast.is_a?(Mal::List)
64 return gen_type Mal::List if ast.empty?
66 sym = ast.first.unwrap
67 eval_error "first element of list must be a symbol" unless sym.is_a?(Mal::Symbol)
69 Mal::Type.new case sym.str
71 eval_error "wrong number of argument for 'def!'" unless ast.size == 3
73 eval_error "1st argument of 'def!' must be symbol" unless a1.is_a?(Mal::Symbol)
74 env.set(a1.str, eval(ast[2], env).as(Mal::Type))
76 eval_error "wrong number of argument for 'def!'" unless ast.size == 3
78 bindings = ast[1].unwrap
79 eval_error "1st argument of 'let*' must be list or vector" unless bindings.is_a?(Array)
80 eval_error "size of binding list must be even" unless bindings.size.even?
82 new_env = Mal::Env.new env
83 bindings.each_slice(2) do |binding|
84 name, value = binding[0].unwrap, binding[1]
85 eval_error "name of binding must be specified as symbol" unless name.is_a?(Mal::Symbol)
86 new_env.set(name.str, eval(value, new_env))
91 f = eval_ast(ast.first, env)
93 args = eval_ast(ast, env)
95 if f.is_a?(Mal::Type) && (f2 = f.unwrap).is_a?(Mal::Func)
96 f2.call(args.as(Array(Mal::Type)))
98 eval_error "expected function symbol as the first symbol of list"
108 print(eval(read(str), REPL_ENV))
112 while line = Readline.readline("user> ", true)
115 rescue e : Mal::RuntimeException
116 STDERR.puts "Error: #{pr_str(e.thrown, true)}"
118 STDERR.puts "Error: #{e}"