Created
January 6, 2011 14:04
-
-
Save mattsan/767917 to your computer and use it in GitHub Desktop.
lisp by ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Global_env = | |
{ | |
'+' => :+, | |
'-' => :-, | |
'*' => :*, | |
'/' => :/, | |
'not' => :not, | |
'>' => :>, | |
'<' => :<, | |
'>=' => :>=, | |
'<=' => :<=, | |
'=' => :==, | |
'equal?' => :==, | |
'eq?' => :instance_of?, | |
'length' => :length, | |
'cons' => Proc.new { |x, xs| [x] + xs }, | |
'car' => Proc.new { |xs| xs[0] }, | |
'cdr' => Proc.new { |xs| xs[1..-1] }, | |
'append' => :+, | |
'list' => Proc.new { |*xs| xs }, | |
'list?' => Proc.new { |xs| xs.instance_of? Array }, | |
'null?' => :empty?, | |
'symbol?' => Proc.new { |x| x.is_a? String } | |
} | |
def eval(x, env = Global_env) | |
if x.instance_of? String | |
env[x] | |
elsif not x.instance_of? Array | |
x | |
elsif x[0] == 'quote' | |
_, exp = x | |
exp | |
elsif x[0] == 'if' | |
_, test, conseq, alt = x | |
eval(if eval(test, env) then conseq else alt end, env) | |
elsif x[0] == 'set!' | |
_, var, exp = x | |
raise "undefined variable" unless env.key?(var) | |
env[var] = eval(exp, env) | |
elsif x[0] == 'define' | |
_, var, exp = x | |
env[var] = eval(exp, env) | |
elsif x[0] == 'lambda' | |
_, vars, exp = x | |
Proc.new { |*args| eval(exp, Hash[vars.zip(args)].merge(env)) } | |
elsif x[0] == 'begin' | |
result = nil | |
x[1..-1].each { |exp| result = eval(exp, env) } | |
result | |
else | |
exps = x.map{ |exp| eval(exp, env) } | |
fn = exps.shift | |
if fn.instance_of? Proc | |
fn.call(*exps) | |
else | |
op1 = exps.shift | |
op1.method(fn).call(*exps) | |
end | |
end | |
end | |
def read(s) | |
read_from tokenize(s) | |
end | |
def tokenize(s) | |
s.gsub('(', ' ( ').gsub(')', ' ) ').split | |
end | |
def read_from(tokens) | |
raise 'unexpected EOF while reading' if tokens.empty? | |
token = tokens.shift | |
if token == '(' | |
l = [] | |
while tokens[0] != ')' | |
l.push read_from(tokens) | |
end | |
tokens.shift | |
l | |
elsif token == ')' | |
raise 'unexpected' | |
else | |
atom(token) | |
end | |
end | |
def atom(token) | |
begin | |
Integer(token) | |
rescue | |
begin | |
Float(token) | |
rescue | |
token | |
end | |
end | |
end | |
class Array | |
def to_s | |
'(' + join(' ') + ')' | |
end | |
end | |
def repl(prompt = 'lis.rb> ') | |
while true | |
print prompt | |
val = read(STDIN.gets) | |
result = eval(val) | |
print "#{result}\n" | |
end | |
end | |
repl if __FILE__ == $0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment