# The visitor pattern is very useful when manipulating expression trees or ASTs # in a non-FP OO language. class Int attr_reader :i def initialize i @i = i end def accept(visitor, arg=nil) visitor.visit_int(self, arg) end end class Neg attr_reader :e def initialize e @e = e end def accept(visitor, arg=nil) visitor.visit_neg(self, arg) end end class Add attr_reader :e1, :e2 def initialize(e1,e2) @e1, @e2 = e1, e2 end def accept(visitor, arg=nil) visitor.visit_add(self, arg) end end SAMPLE = Neg.new(Add.new(Add.new(Add.new(Int.new(3), Neg.new(Int.new 9)), Int.new(-42)), Add.new(Int.new(73), Neg.new(Int.new(14))))) # ... # # Pretty print the expression. # class Stringer # def visit_int(int, arg) # int.i.to_s # end # def visit_neg(neg, arg) # "-(" + neg.e.accept(self) + ")" # end # def visit_add(add, arg) # "(" + add.e1.accept(self) + " + " + add.e2.accept(self) + ")" # end # end # # # SAMPLE.accept(Stringer.new) # # # Evaluate the expression. # class Evaluator # def visit_int(int, arg) # int # end # def visit_neg(neg, arg) # Int.new(- neg.e.accept(self).i) # end # def visit_add(add, arg) # Int.new(add.e1.accept(self).i + add.e2.accept(self).i) # end # end # # # SAMPLE.accept(Evaluator.new).accept(Stringer.new) # # # # Make sure only positive constants are used. # # All negative numbers in the resulting expression # # are expressed as Negs. # class Positivator # def visit_int(int, arg) # if int.i < 0 # Neg.new(Int.new(-int.i)) # else # int # end # end # def visit_neg(neg, arg) # Neg.new(neg.e.accept(self)) # end # def visit_add(add, arg) # Add.new(add.e1.accept(self), add.e2.accept(self)) # end # end # # # SAMPLE.accept(Positivator.new).accept(Stringer.new) # # SAMPLE.accept(Positivator.new).accept(Evaluator.new).accept(Stringer.new) # # # # Only allow Negs of Ints. No Adds under Negs. # class NegLeafer # def visit_int(int, flip) # if flip # Neg.new(int) # else # int # end # end # def visit_neg(neg, flip) # neg.e.accept(self, !flip) # end # def visit_add(add, flip) # Add.new(add.e1.accept(self, flip), add.e2.accept(self, flip)) # end # end # # # SAMPLE.accept(Positivator.new).accept(NegLeafer.new).accept(Stringer.new) # # SAMPLE.accept(Positivator.new).accept(NegLeafer.new).accept(Evaluator.new).accept(Stringer.new)