Skip to content

Instantly share code, notes, and snippets.

@zetter
Forked from floehopper/atom.rb
Last active August 29, 2015 13:56
Show Gist options
  • Save zetter/8792095 to your computer and use it in GitHub Desktop.
Save zetter/8792095 to your computer and use it in GitHub Desktop.
class Atom
attr_reader :symbol
def initialize(symbol)
@symbol = symbol
end
def ==(other)
self.symbol == other.symbol
end
end
class Evaluator
def initialize(program)
@program = program
end
def evaluate(env={})
function, argument = @program.car, @program.cdr.car
operation = function.symbol
case argument
when Atom
env[argument.symbol].send(operation)
when List
self.class.new(argument).evaluate(env).send(operation)
else
raise
end
end
end
require 'minitest/autorun'
require_relative 'atom'
require_relative 'list'
require_relative 'evaluator'
class EvaluatorTest < Minitest::Test
def test_car
assert_equal Atom.new(:a), evaluate(
List.new(Atom.new(:car), Atom.new(:l)),
l: List.new(Atom.new(:a), Atom.new(:b), Atom.new(:c))
)
end
def test_car_car
assert_equal Atom.new(:hotdogs), evaluate(
List.new(Atom.new(:car), List.new(Atom.new(:car), Atom.new(:l))),
l: List.new(List.new(Atom.new(:hotdogs), Atom.new(:and)))
)
end
def test_cdr
assert_equal List.new(Atom.new(:b), Atom.new(:c)), evaluate(
List.new(Atom.new(:cdr), Atom.new(:l)),
l: List.new(Atom.new(:a), Atom.new(:b), Atom.new(:c))
)
end
private
def evaluate(program, env={})
Evaluator.new(program).evaluate(env)
end
end
class List
def initialize(*array)
@array = array
end
def car
@array.first
end
def cdr
self.class.new(*@array[1..-1])
end
def ==(other)
self.array == other.array
end
protected
attr_reader :array
end
grammar Scheme
rule sexp
atom / list
end
rule list
'(' sexps:(sexp ' '?)* ')' {
def to_ast
list_contents = sexps.elements.map{|element| element.sexp.to_ast }
List.new(*list_contents)
end
}
end
rule atom
[0-9a-z]+ {
def to_ast
Atom.new(text_value)
end
}
end
end
require 'treetop'
require 'atom'
require 'list'
require 'evaluator'
Treetop.load('scheme.treetop')
parser = SchemeParser.new
program = parser.parse("(car (cdr l))").to_ast
l = parser.parse("(1 2 3)").to_ast
p Evaluator.new(program).evaluate({"l" => l})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment