220 lines
6.4 KiB
Python
220 lines
6.4 KiB
Python
# # 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)
|