sandbox/uc/py/simple.py

220 lines
6.4 KiB
Python
Raw Normal View History

2018-01-16 17:46:44 +00:00
# # The Meaning of Programs
# Let's define a simple *AST*, with three basic members. An AST node can
# be reducible, like the + in (2 + 2), or not-reducible, like the
# number 2. We'll also reduce from left to right.
class Number:
def __init__(self, value):
self.value = int(value)
def __repr__(self):
return "#" + str(self.value)
def is_reducible(self):
return False
class Add:
def __init__(self, l, r):
self.left = l
self.right = r
def __repr__(self):
return repr(self.left) + " + " + repr(self.right)
def is_reducible(self):
return True
def reduce(self, env):
if self.left.is_reducible():
return Add(self.left.reduce(env), self.right)
elif self.right.is_reducible():
return Add(self.left, self.right.reduce(env))
else:
return Number(self.left.value + self.right.value)
class Mult:
def __init__(self, l, r):
self.left = l
self.right = r
def __repr__(self):
return repr(self.left) + " * " + repr(self.right)
def is_reducible(self):
return True
def reduce(self, env):
if self.left.is_reducible():
return Mult(self.left.reduce(env), self.right)
elif self.right.is_reducible():
return Mult(self.left, self.right.reduce(env))
else:
return Number(self.left.value * self.right.value)
ast1 = Add(Mult(Number(1), Number(2)),
Mult(Number(3), Number(4)))
# It would be nice to have a machine that could run these, so we don't
# have to run them by hand.
class Machine:
def __init__(self, expr, env):
self.expr = expr
self.env = env
self.iters = 0
def step(self):
self.iters += 1
self.expr = self.expr.reduce(self.env)
def run(self):
while self.expr.is_reducible():
print self
self.step()
print "execution complete in ", self.iters, " steps."
return self.expr
def __repr__(self):
return "(" + str(self.iters) + ") " + repr(self.expr) + "\n" + repr(self.env)
class Boolean:
def __init__(self, value):
self.value = value
def __repr__(self):
return str(self.value).lower()
def is_reducible(self):
return False
class LessThan:
def __init__(self, l, r):
self.left = l
self.right = r
def __repr__(self):
return repr(self.left) + " < " + repr(self.right)
def is_reducible(self):
return True
def reduce(self, env):
if self.left.is_reducible():
return LessThan(self.left.reduce(env), self.right)
elif self.right.is_reducible():
return LessThan(self.left, self.right.reduce(env))
else:
return Boolean(self.left.value < self.right.value)
ast2 = LessThan(Number(5), Add(Number(2), Number(2)))
ast2b = LessThan(Add(Number(2), Number(2)), Number(5))
class Variable:
def __init__(self, name):
self.name = name
def __repr__(self):
return "$" + self.name
def is_reducible(self):
return True
def reduce(self, env):
return env[self.name]
ast3 = Add(Variable('x'), Variable('y'))
env3 = {'x': Number(3), 'y': Number(4)}
m3 = lambda : Machine(ast3, env3)
class Nop:
def __init__(self):
pass
def __repr__(self):
return "@NOP"
def eq(self, st):
return st.instanceof(Nop)
def is_reducible(self):
return False
class Assign:
def __init__(self, name, expr):
self.name = name
self.expr = expr
def __repr__(self):
return self.name + " = " + repr(self.expr)
def is_reducible(self):
return True
def reduce(self, env):
if self.expr.is_reducible():
return Assign(self.name, self.expr.reduce(env)), env.copy()
else:
env[self.name] = self.expr
return Nop(), env.copy()
stmt4 = Assign("x", Add(Variable("x"), Number(1)))
env4 = {"x": Number(2)}
class Machine2:
def __init__(self, stmt, env):
self.stmt = stmt
self.env = env
self.iters = 0
def __repr__(self):
return "(" + str(self.iters) + ") " + repr(self.stmt) + "\n" + repr(self.env)
def step(self):
self.iters += 1
self.stmt, self.env = self.stmt.reduce(self.env)
print self
def run(self):
while self.stmt.is_reducible():
self.step()
print "execution complete in ", self.iters, " steps."
print self
stmt5 = Assign("x", Add(Variable("x"), Number(1)))
env5 = {"x": Number(2)}
m5 = lambda : Machine2(stmt5, env5)
class If:
def __init__(self, cond, cons, alt):
self.cond = cond
self.cons = cons
self.alt = alt
def __repr__(self):
s = "if |" + repr(self.cond) + "| then |" + repr(self.cons)
return s + "| else |" + repr(self.alt) + "|"
def is_reducible(self):
return True
def reduce(self, env):
if self.cond.is_reducible():
return If(self.cond.reduce(env), self.cons, self.alt), env.copy()
elif self.cond.value:
return self.cons, env.copy()
else:
return self.alt, env.copy()
stmt6 = If(Variable("x"), Assign("y", Number(1)), Assign("y", Number(2)))
env6 = {"x": Boolean(True)}
m6 = lambda : Machine2(stmt6, env6)
class Sequence:
def __init__(self, first, second):
self.first = first
self.second = second
def __repr__(self):
return repr(self.first) + ";" + repr(self.second)
def is_reducible(self):
return True
def reduce(self, env):
if isinstance(self.first, Nop):
return self.second, env.copy()
else:
first, env = self.first.reduce(env)
return Sequence(first, self.second), env.copy()
stmt7 = Sequence(Assign("x", Add(Number(1), Number(1))),
Assign("y", Add(Variable("x"), Number(3))))
env7 = {}
m7 = lambda : Machine2(stmt7, env7)
class While:
def __init__(self, cond, body):
self.cond = cond
self.body = body
def __repr__(self):
return "while |" + repr(self.cond) + "|:\n\t" + repr(self.body)
def is_reducible(self):
return True
def reduce(self, env):
return If(self.cond, Sequence(self.body, self), Nop()), env.copy()
stmt8 = While(LessThan(Variable("x"), Number(5)),
Assign("x", Mult(Variable("x"), Number(3))))
env8 = {"x": Number(1)}
m8 = lambda : Machine2(stmt8, env8)