summaryrefslogtreecommitdiff
path: root/simple/simple.rb
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple.rb')
-rw-r--r--simple/simple.rb196
1 files changed, 196 insertions, 0 deletions
diff --git a/simple/simple.rb b/simple/simple.rb
new file mode 100644
index 0000000..a31e001
--- /dev/null
+++ b/simple/simple.rb
@@ -0,0 +1,196 @@
+#!/usr/bin/ruby
+
+class Value < Struct.new(:value)
+ def to_s
+ value.to_s
+ end
+ def inspect
+ "<#{self}>"
+ end
+ def reducible?
+ false
+ end
+end
+
+class Number < Value
+end
+
+class Boolean < Value
+end
+
+class Variable < Struct.new(:name)
+ def to_s
+ name.to_s
+ end
+
+ def inspect
+ "<#{self}>"
+ end
+
+ def reduce(environment)
+ environment[name]
+ end
+
+ def reducible?
+ true
+ end
+end
+
+class BiOp < Struct.new(:left, :right)
+ def inspect
+ "<#{self}>"
+ end
+ def reducible?
+ true
+ end
+end
+
+class Add < BiOp
+ def to_s
+ "#{left} + #{right}"
+ end
+ def reduce(environment)
+ if left.reducible?
+ Add.new(left.reduce(environment),right)
+ elsif right.reducible?
+ Add.new(left,right.reduce(environment))
+ else
+ Number.new(left.value+right.value)
+ end
+ end
+end
+
+class Multiply < BiOp
+ def to_s
+ "#{left} * #{right}"
+ end
+ def reduce(environment)
+ if left.reducible?
+ Add.new(left.reduce(environment),right)
+ elsif right.reducible?
+ Add.new(left,right.reduce(environment))
+ else
+ Number.new(left.value*right.value)
+ end
+ end
+end
+
+class LessThan < BiOp
+ def to_s
+ "#{left} < #{right}"
+ end
+
+ def reduce(environment)
+ if left.reducible?
+ LessThan.new(left.reduce(environment), right)
+ elsif right.reducible?
+ LessThan.new(left, right.reduce(environment))
+ else
+ Boolean.new(left.value < right.value)
+ end
+ end
+end
+
+class DoNothing
+ def to_s
+ 'do-nothing'
+ end
+
+ def inspect
+ "<#{self}>"
+ end
+
+ def ==(other_statement)
+ other_statement.instance_of?(DoNothing)
+ end
+
+ def reducible?
+ false
+ end
+end
+
+class Assign < Struct.new(:name, :expression)
+ def to_s
+ "#{name} = #{expression}"
+ end
+
+ def inspect
+ "<#{self}>"
+ end
+
+ def reducible?
+ true
+ end
+
+ def reduce(environment)
+ if expression.reducible?
+ [Assign.new(name, expression.reduce(environment)), environment]
+ else
+ [DoNothing.new, environment.merge({name => expression })]
+ end
+ end
+end
+
+class If < Struct.new(:condition, :consequence, :alternative)
+ def to_s
+ "if (#{condition}) { #{consequence} } else { #{alternative} }"
+ end
+
+ def inspect
+ "<#{self}>"
+ end
+
+ def reducible?
+ true
+ end
+
+ def reduce(environment)
+ if condition.reducible?
+ [If.new(condition.reduce(environment), consequence, alternative), environment]
+ else
+ case condition
+ when Boolean.new(true)
+ [consequence, environment]
+ when Boolean.new(false)
+ [alternative, environment]
+ end
+ end
+ end
+end
+
+class Sequence < Struct.new(:first, :second)
+ def to_s
+ "#{first}; #{second}"
+ end
+
+ def inspect
+ "<#{self}>"
+ end
+
+ def reducible?
+ true
+ end
+
+ def reduce(environment)
+ case first
+ when DoNothing.new
+ [second,environment]
+ else
+ reduced_first, reduced_environment = first.reduce(environment)
+ [Sequence.new(reduced_first, second), reduced_environment]
+ end
+
+class Machine < Struct.new(:statement, :environment)
+ def step
+ self.statement, self.environment = statement.reduce(environment)
+ end
+
+ def run
+ while statement.reducible?
+ puts "#{statement}, #{environment}"
+ step
+ end
+
+ puts "#{statement}, #{environment}"
+ end
+end