Skip to content

Instantly share code, notes, and snippets.

@agenticsim
Forked from p8/lithp.rb
Created January 5, 2013 05:24
Show Gist options
  • Save agenticsim/4459928 to your computer and use it in GitHub Desktop.
Save agenticsim/4459928 to your computer and use it in GitHub Desktop.
class Lisp
Fs = Hash.new(lambda {|fn, *sexp| [fn] + sexp }).merge({
:label => lambda {|name, value| Fs[name] = lambda { value } },
:eq => lambda {|a,b| a == b },
:quote => lambda {|value| value },
:car => lambda {|list| list[0] },
:cdr => lambda {|list| list.slice(1, list.size) },
:cons => lambda {|value, list| [value[0]] + list },
:if => lambda {|condition, thn, els| condition ? thn : els },
:atom => lambda {|value| !value.is_a? Array },
:apply => lambda {|*sexp| Fs.key?(sexp[0]) ? Fs[sexp[0]].call(*sexp.slice(1, sexp.size)) : sexp[0] }
})
def self.eval sexp
fn, *args = sexp
if Fs.key?(fn)
sexp = args.map{|a| Fs[:atom].call(a) ? Fs[:apply].call(a) : eval(a) }
end
Fs[fn].call(*sexp)
end
end
def assert_equal(a, b)
a == b or raise "#{a.inspect} should equal #{b.inspect}"
end
l = Lisp
l.eval [:label, :a, 42]
assert_equal 42, l.eval([:a])
assert_equal true, l.eval([:eq, 42, :a])
assert_equal true, l.eval([:eq, :a, 42])
assert_equal [1,2], l.eval([:quote, [1, 2]])
assert_equal 1, l.eval([:car, [:quote, [1, 2]]])
assert_equal [2], l.eval([:cdr, [:quote, [1, 2]]])
assert_equal [1,2,3], l.eval([:cons, 1, [:quote, [2,3]]])
assert_equal 43, l.eval([:if, [:eq, 1, 2], 42, 43])
assert_equal false, l.eval([:atom, [:quote, [1,2]]])
assert_equal true, l.eval([:atom, 1])
assert_equal true, l.eval([:eq, [:quote, [1, 2, 3]], [:cons, 1, [:quote, [2,3]]]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment