-
Notifications
You must be signed in to change notification settings - Fork 0
/
terp.py
126 lines (100 loc) · 3.05 KB
/
terp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from clutch import Clutch, Box
from env import Env, EmptyEnv
def run(expr, env):
state = start(expr, env)
while state.is_runnable():
state = state.step()
return state.get_value()
def start(expr, env):
return expr.eval(env, FinalK())
# States
def RunningState(value, k):
def to_is_runnable(): return True
def to_step(): return k.step(value)
def to_trace(): return repr((value, k))
def to___repr__(): return repr((value, k))
return Clutch(locals())
def StoppedState(value):
def to_is_runnable(): return False
def to_step(): assert False, 'Stopped process stepped'
def to_trace(): return '<stopped>'
def to___repr__(): return '<stopped>'
def to_get_value(): return value
return Clutch(locals())
# Continuations
class Cont(Clutch):
def __str__(self):
return '\n'.join(reversed(self.get_backtrace()))
def __repr__(self):
return '|'.join(self.get_backtrace())
def get_backtrace(self):
return [k.show_frame() for k in ancestry(self)]
def ancestry(k):
while True:
yield k
k = k.get_parent()
if k is None:
break
def FinalK():
def to_step(value):
return StoppedState(value)
def to_show_frame():
return '<stop>'
def to_get_parent():
return None
return Cont(locals())
# AST types
def ConstantExpr(value):
def to_eval(env, k):
return RunningState(value, k)
def to___repr__():
return "'" + repr(value)
return Clutch(locals())
def VarRefExpr(variable):
def to_eval(env, k):
return RunningState(env.get(variable), k)
def to___repr__():
return repr(variable)
return Clutch(locals())
def LambdaExpr(variable, expr):
def to_eval(env, k):
return RunningState(Procedure(env, variable, expr), k)
def to___repr__():
return '(lambda %s %r)' % (variable, expr)
def to_make_closure(env):
return Procedure(env, variable, expr)
return LambdaExprClass(locals())
class LambdaExprClass(Clutch): pass
def Procedure(env, variable, expr):
def to_call(arg, k):
return expr.eval(Env(variable, arg, env), k)
def to___repr__():
return '#<procedure>'
return Clutch(locals())
def CallExpr(rator, rand):
def to_eval(env, k):
return rator.eval(env, EvRandK(rand, env, k, rator))
def to___repr__():
return '(%r %r)' % (rator, rand)
return Clutch(locals())
def EvRandK(rand, env, k, rator):
def to_step(fn):
return rand.eval(env, CallK(fn, env, k, rator, rand))
def to_show_frame():
return '(<%r> %r)' % (rator, rand)
def to_get_parent():
return k
return Cont(locals())
def CallK(fn, env, k, rator, prev_rands):
def to_step(arg):
return fn.call(arg, k)
def to_show_frame():
return '(<%r %r>)' % (rator, rand)
def to_get_parent():
return k
return Cont(locals())
# Smoke test
one = ConstantExpr(1)
f = LambdaExpr('x', VarRefExpr('x'))
test1 = CallExpr(f, one)
print run(test1, EmptyEnv())