A fork of Crisp for HARP
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 

90 lignes
1.8 KiB

#! /usr/bin/env crystal run
require "./readline"
require "./reader"
require "./printer"
require "./types"
# Note:
# Employed downcase names because Crystal prohibits uppercase names for methods
def eval_error(msg)
raise Mal::EvalException.new msg
end
def num_func(func)
-> (args : Array(Mal::Type)) {
x, y = args[0].unwrap, args[1].unwrap
eval_error "invalid arguments" unless x.is_a?(Int32) && y.is_a?(Int32)
Mal::Type.new func.call(x, y)
}
end
$repl_env = {
"+" => num_func(->(x : Int32, y : Int32){ x + y }),
"-" => num_func(->(x : Int32, y : Int32){ x - y }),
"*" => num_func(->(x : Int32, y : Int32){ x * y }),
"/" => num_func(->(x : Int32, y : Int32){ x / y }),
} of String => Mal::Func
def eval_ast(a, env)
return a.map{|n| eval(n, env) as Mal::Type} if a.is_a? Mal::List
return a unless a
ast = a.unwrap
case ast
when Mal::Symbol
if env.has_key? ast.str
env[ast.str]
else
eval_error "'#{ast.str}' not found"
end
when Mal::List
ast.each_with_object(Mal::List.new){|n, l| l << eval(n, env)}
when Mal::Vector
ast.each_with_object(Mal::Vector.new){|n, l| l << eval(n, env)}
when Mal::HashMap
ast.each{|k, v| ast[k] = eval(v, env)}
else
ast
end
end
def read(str)
read_str str
end
def eval(t, env)
Mal::Type.new case ast = t.unwrap
when Mal::List
eval_error "empty list" if ast.empty?
f = eval_ast(ast.first, env)
ast.shift(1)
args = eval_ast(ast, env)
if f.is_a?(Mal::Func)
f.call(args)
else
eval_error "expected function symbol as the first symbol of list"
end
else
eval_ast(t, env)
end
end
def print(result)
pr_str(result, true)
end
def rep(str)
print(eval(read(str), $repl_env))
end
while line = my_readline("user> ")
begin
puts rep(line)
rescue e
STDERR.puts e
end
end