Skip to content

Commit e2f850f

Browse files
committed
lambda
1 parent fc9b03e commit e2f850f

File tree

4 files changed

+188
-0
lines changed

4 files changed

+188
-0
lines changed

interp_Clambda.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from ast import *
2+
from interp_Cfun import InterpCfun
3+
from utils import *
4+
5+
class InterpClambda(InterpCfun):
6+
7+
def interp_exp(self, e, env):
8+
match e:
9+
case AllocateClosure(length, typ, arity):
10+
array = [None] * length
11+
return array
12+
case _:
13+
return super().interp_exp(e, env)

interp_Llambda.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from ast import *
2+
from interp_Lfun import InterpLfun, Function
3+
from utils import *
4+
5+
class InterpLlambda(InterpLfun):
6+
7+
def interp_exp(self, e, env):
8+
match e:
9+
case FunRefArity(id, arity):
10+
return env[id]
11+
case Lambda(params, body):
12+
return Function('lambda', params, [Return(body)], env)
13+
case Closure(arity, args):
14+
return tuple([self.interp_exp(arg, env) for arg in args])
15+
case AllocateClosure(length, typ, arity):
16+
array = [None] * length
17+
return array
18+
case _:
19+
return super().interp_exp(e, env)
20+
21+
def interp_stmts(self, ss, env):
22+
if len(ss) == 0:
23+
return
24+
match ss[0]:
25+
case AnnAssign(lhs, typ, value, simple):
26+
env[lhs.id] = self.interp_exp(value, env)
27+
return self.interp_stmts(ss[1:], env)
28+
case _:
29+
return super().interp_stmts(ss, env)
30+

type_check_Clambda.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from utils import AllocateClosure
2+
from type_check_Cfun import TypeCheckCfun
3+
4+
class TypeCheckClambda(TypeCheckCfun):
5+
6+
def type_check_exp(self, e, env):
7+
match e:
8+
case AllocateClosure(length, typ, arity):
9+
return typ
10+
case _:
11+
return super().type_check_exp(e, env)
12+

type_check_Llambda.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import ast
2+
from ast import *
3+
from type_check_Lfun import TypeCheckLfun
4+
from utils import *
5+
import typing
6+
7+
# This type checker uses bidirectional type checking to work-around
8+
# the lack of type annotations in Python's lambdas.
9+
10+
class TypeCheckLlambda(TypeCheckLfun):
11+
12+
def type_check_exp(self, e, env):
13+
match e:
14+
case Name(id):
15+
e.has_type = env[id]
16+
return env[id]
17+
case FunRefArity(id, arity):
18+
return env[id]
19+
case Closure(arity, es):
20+
ts = [self.type_check_exp(e, env) for e in es]
21+
e.has_type = TupleType(ts)
22+
return e.has_type
23+
case Lambda(params, body):
24+
raise Exception('cannot synthesize a type for a lambda')
25+
case _:
26+
return super().type_check_exp(e, env)
27+
28+
def check_exp(self, e, ty, env):
29+
match e:
30+
case Lambda(params, body):
31+
e.has_type = ty
32+
#trace('*** tc_check lambda ' + repr(ty) + '\n')
33+
if isinstance(params, ast.arguments):
34+
new_params = [a.arg for a in params.args]
35+
e.args = new_params
36+
else:
37+
new_params = params
38+
match ty:
39+
case FunctionType(params_t, return_t):
40+
new_env = {x:t for (x,t) in env.items()}
41+
for (p,t) in zip(new_params, params_t):
42+
new_env[p] = t
43+
self.check_exp(body, return_t, new_env)
44+
case Bottom():
45+
pass
46+
case _:
47+
raise Exception('lambda does not have type ' + str(ty))
48+
case Call(Name('input_int'), []):
49+
return int
50+
case Call(func, args):
51+
func_t = self.type_check_exp(func, env)
52+
match func_t:
53+
case FunctionType(params_t, return_t):
54+
for (arg, param_t) in zip(args, params_t):
55+
self.check_exp(arg, param_t, env)
56+
self.check_type_equal(return_t, ty, e)
57+
case _:
58+
raise Exception('type_check_exp: in call, unexpected ' + \
59+
repr(func_t))
60+
case _:
61+
t = self.type_check_exp(e, env)
62+
self.check_type_equal(t, ty, e)
63+
64+
def check_stmts(self, ss, return_ty, env):
65+
if len(ss) == 0:
66+
return
67+
#trace('*** check_stmts ' + repr(ss[0]) + '\n')
68+
match ss[0]:
69+
case FunctionDef(name, params, body, dl, returns, comment):
70+
#trace('*** tc_check ' + name)
71+
new_env = {x: t for (x,t) in env.items()}
72+
if isinstance(params, ast.arguments):
73+
new_params = [(p.arg, self.parse_type_annot(p.annotation)) for p in params.args]
74+
ss[0].args = new_params
75+
new_returns = self.parse_type_annot(returns)
76+
ss[0].returns = new_returns
77+
else:
78+
new_params = params
79+
new_returns = returns
80+
for (x,t) in new_params:
81+
new_env[x] = t
82+
rt = self.check_stmts(body, new_returns, new_env)
83+
self.check_stmts(ss[1:], return_ty, env)
84+
case Return(value):
85+
#trace('** tc_check return ' + repr(value))
86+
self.check_exp(value, return_ty, env)
87+
case Assign([Name(id)], value):
88+
if id in env:
89+
self.check_exp(value, env[id], env)
90+
else:
91+
env[id] = self.type_check_exp(value, env)
92+
self.check_stmts(ss[1:], return_ty, env)
93+
case Assign([Subscript(tup, Constant(index), Store())], value):
94+
tup_t = self.type_check_exp(tup, env)
95+
match tup_t:
96+
case TupleType(ts):
97+
self.check_exp(value, ts[index], env)
98+
case Bottom():
99+
pass
100+
case _:
101+
raise Exception('check_stmts: expected a tuple, not ' \
102+
+ repr(tup_t))
103+
self.check_stmts(ss[1:], return_ty, env)
104+
case AnnAssign(Name(id), ty, value, simple):
105+
ty_annot = self.parse_type_annot(ty)
106+
ss[0].annotation = ty_annot
107+
if id in env:
108+
self.check_type_equal(env[id], ty_annot)
109+
else:
110+
env[id] = ty_annot
111+
self.check_exp(value, ty_annot, env)
112+
self.check_stmts(ss[1:], return_ty, env)
113+
case _:
114+
self.type_check_stmts(ss, env)
115+
116+
117+
def type_check(self, p):
118+
#trace('*** type check Llambda')
119+
match p:
120+
case Module(body):
121+
env = {}
122+
for s in body:
123+
match s:
124+
case FunctionDef(name, params, bod, dl, returns, comment):
125+
if isinstance(params, ast.arguments):
126+
params_t = [self.parse_type_annot(p.annotation) \
127+
for p in params.args]
128+
else:
129+
params_t = [t for (x,t) in params]
130+
env[name] = FunctionType(params_t, self.parse_type_annot(returns))
131+
self.check_stmts(body, int, env)
132+
case _:
133+
raise Exception('type_check: unexpected ' + repr(p))

0 commit comments

Comments
 (0)