Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 71 lines (61 sloc) 1.77 KB
#!/usr/bin/env ruby
class Env < Hash
def initialize(keys=[], vals=[], outer=nil)
@outer = outer
keys.zip(vals).each{|p| store(*p)}
end
def [](name)
super(name) || @outer[name]
end
def set(name, value)
key?(name) ? store(name, value) : @outer.set(name, value)
end
end
def init(env)
[:+, :-, :*, :/, :>, :<, :>=, :<=, :==].each do |op|
env[op] = lambda{|a, b| a.send(op, b)}
end
env.update({ :length => lambda{|x| x.length}, :cons => lambda{|x, y| [x]+y},
:car => lambda{|x| x[0]}, :cdr => lambda{|x| x[1..-1]}, :append => lambda{|x,y| x+y},
:list => lambda{|*xs| xs}, :list? => lambda{|x| x.is_a? Array}, :null? => lambda{|x| x==nil},
:symbol? => lambda{|x| x.is_a? Symbol}, :not => lambda{|x| !x}, :display => lambda{|x| p x}})
end
def eval(x, env)
return env[x] if x.is_a? Symbol
return x if !x.is_a? Array
case x[0]
when :quote then x[1..-1]
when :define then env[x[1]] = eval(x[2], env)
when :set! then env.set(x[1], eval(x[2], env))
when :env then env
when :if
_, test, conseq, alt = x
eval(eval(test, env) ? conseq : alt, env)
when :lambda
_, vars, exp = x
Proc.new{|*args| eval(exp, Env.new(vars, args, env))}
when :begin
x[1..-1].inject([nil, env]){|val_env, exp| [eval(exp, val_env[1]), val_env[1]]}[0]
else
exps = x.map{|exp| eval(exp, env)}
exps[0].call(*exps[1..-1])
end
end
def to_atom(src)
return "[" if src =='('
return "]" if src ==')'
return src if src =~ /^-?\d+$/ || src =~ /^-?\d*\.\d+$/
':' + src
end
def read(src)
tokens = src.gsub('(', ' ( ').gsub(')', ' ) ').split
Kernel.eval(tokens.map{|s| to_atom(s)}.join(' ').gsub(' ]',']').gsub(/([^\[]) /,'\1, '))
end
def repl
env = init(Env.new)
while true
"geeklisp> ".display
p(eval(read(gets), env))
end
end
repl