main
  1require "spec_helper"
  2
  3class Machine < Struct.new(:expression, :environment)
  4  def step
  5    self.expression = expression.reduce(environment)
  6  end
  7
  8  def run
  9    while expression.reducible?
 10      puts expression
 11      step
 12    end
 13    puts expression
 14  end
 15end
 16
 17class Number < Struct.new(:value)
 18  def reducible?
 19    false
 20  end
 21
 22  def to_s
 23    value.to_s
 24  end
 25
 26  def inspect
 27    "<<#{self}>>"
 28  end
 29end
 30
 31class Add < Struct.new(:left, :right)
 32  def reducible?
 33    true
 34  end
 35
 36  def reduce(environment)
 37    if left.reducible?
 38      Add.new(left.reduce(environment), right)
 39    elsif right.reducible?
 40      Add.new(left, right.reduce(environment))
 41    else
 42      Number.new(left.value + right.value)
 43    end
 44  end
 45
 46  def to_s
 47    "(#{left} + #{right})"
 48  end
 49
 50  def inspect
 51    "<<#{self}>>"
 52  end
 53end
 54
 55class Multiply < Struct.new(:left, :right)
 56  def reducible?
 57    true
 58  end
 59
 60  def reduce(environment)
 61    if left.reducible?
 62      Multiple.new(left.reduce(environment), right)
 63    elsif right.reducible?
 64      Multiple.new(left, right.reduce(environment))
 65    else
 66      Number.new(left.value * right.value)
 67    end
 68  end
 69
 70  def to_s
 71    "(#{left} * #{right})"
 72  end
 73
 74  def inspect
 75    "<<#{self}>>"
 76  end
 77end
 78
 79class Boolean < Struct.new(:value)
 80  def to_s
 81    value.to_s
 82  end
 83
 84  def inspect
 85    "<<#{self}>>"
 86  end
 87
 88  def reducible?
 89    false
 90  end
 91end
 92
 93class LessThan < Struct.new(:left, :right)
 94  def to_s
 95    "#{left} < #{right}"
 96  end
 97
 98  def inspect
 99    "<<#{self}>>"
100  end
101
102  def reducible?
103    true
104  end
105
106  def reduce(environment)
107    if left.reducible?
108      LessThan.new(left.reduce(environment), right)
109    elsif right.reducible?
110      LessThan.new(left, right.reduce(environment))
111    else
112      Boolean.new(left.value < right.value)
113    end
114  end
115end
116
117class Variable < Struct.new(:name)
118  def to_s
119    name.to_s
120  end
121
122  def inspect
123    "<<#{self}>>"
124  end
125
126  def reducible?
127    true
128  end
129
130  def reduce(environment)
131    environment[name]
132  end
133end
134
135describe "expressions" do
136  it "can do math" do
137    machine = Machine.new(Add.new(Multiply.new(Number.new(1), Number.new(2)), Multiply.new(Number.new(3), Number.new(4))))
138    result = machine.run
139    puts result
140  end
141
142  it "can check less than" do
143    puts Machine.new(LessThan.new(Number.new(5), Add.new(Number.new(2), Number.new(2)))).run
144  end
145
146  it "can assign variables" do
147    environment = { x: Number.new(3), y: Number.new(4) }
148    puts Machine.new(Add.new(Variable.new(:x), Variable.new(:y)), environment).run
149  end
150end