def _check_Call_expr(call, t, env): """Application.""" assert call.__class__ is ast.Call f = call.func a = call.args k = call.keywords s = call.starargs kw = call.kwargs # All App rules have specific forms for keywords, starargs, and kwargs. if not k and not s and not kw: # (App1) assignment rule. if not a: return check_expr(f, PType.arrow(unit_t, t), env) # (App2) assignment rule. elif len(a) == 1 and f.__class__ is ast.Name: f_t = env_get(env, f.id) return check_expr(a[0], f_t.dom, env) and f_t.ran == t # (App3) assignment rule. elif f.__class__ is ast.Name: f_t = env_get(env, f.id) tup = ast.Tuple([b for b in a], ast.Load()) return check_expr(tup, f_t.dom, env) and f_t.ran == t # No assignment rule found. return False
def _check_Expr_stmt(stmt, env): """Expression Statement.""" assert stmt.__class__ is ast.Expr e = stmt.value # (Expr-Stmt) assignment rule if e.__class__ is ast.Call and e.func.__class__ is ast.Name: f = e.func f_t = env_get(env, f.id) return check_expr(e, f_t.ran, env) # No assignment rule found. else: return False
def _check_Return_stmt(stmt, env): """Return Statement.""" assert stmt.__class__ is ast.Return e = stmt.value try: r_t = env_get(env, "return") except TypeUnspecifiedError: return False # (RetU) assignment rule. if not e: return r_t == unit_t # (Ret) assignment rule. else: return check_expr(e, r_t, env)
def _check_Name_expr(name, t, env): """Identifiers.""" assert name.__class__ is ast.Name x = name.id base_env = {"True" : bool_t, "False" : bool_t, "None" : unit_t} # (Base-Env) assignment rule. if x in base_env: return t == base_env[x] # (Idn) assignment rule. elif env_get(env, x) == t: return True # No assignment rule found. else: return False
def _check_FunctionDef_stmt(stmt, env): """Function Definition.""" assert stmt.__class__ is ast.FunctionDef f = stmt.name a = stmt.args b = stmt.body d = stmt.decorator_list # All Fn-Def rules have specific forms for args and decorator_list. if (all(arg.__class__ is ast.Name for arg in a.args) and not a.vararg and not a.kwarg and not a.defaults and not d): f_t = env_get(env, f) # (Fn-Def1) assignment rule. if not a.args: new_env = dict(env.items() + [("return", f_t.ran)]) return check_stmt_list(b, new_env) # (Fn-Def2) assignment rule. elif len(a.args) == 1 and f_t.dom != unit_t: arg_id = a.args[0].id new_env = dict(env.items() + [(arg_id, f_t.dom), ("return", f_t.ran)]) return check_stmt_list(b, new_env) # (Fn-Def3) assignment rule. elif f_t.dom.is_tuple() and f_t.dom.tuple_len() == len(a.args): arg_ids = map(lambda x: x.id, a.args) arg_ts = f_t.dom.elts new_env = dict(env.items() + zip(arg_ids, arg_ts) + [("return", f_t.ran)]) return check_stmt_list(b, new_env) # No assignment rule found. return False
def check_stmt_list(stmts, env): """ Check whether each stmt in `stmts` typechecks correctly. `env` is the common type environment shared by all stmts in `stmts` """ # (Stmts-Base) assignment rule. if not stmts: return True # (Stmts) assignment rule. elif stmts[0].__class__ is not TypeDec: return check_stmt(stmts[0], env) and check_stmt_list(stmts[1:], env) # (Stmts-LetA) assignment rule. elif (stmts[1].__class__ is ast.Assign and len(stmts[0].targets) == 1 and len(stmts[1].targets) == 1 and stmts[0].targets[0].__class__ is ast.Name and stmts[1].targets[0].__class__ is ast.Name and stmts[0].targets[0].id == stmts[1].targets[0].id): tdec = stmts[0] tar_id = tdec.targets[0].id assmt = stmts[1] # Throw an error if the typedec target has already been declared with a # different type. try: tar_t = env_get(env, tar_id) if tar_t != tedc.t: raise TypeMultiSpecifiedError() except TypeUnspecifiedError: pass new_env = dict(env) new_env[tar_id] = tdec.t.quantify() return (check_expr(assmt.value, tdec.t, env) and check_stmt_list(stmts[2:], new_env)) # (Stmts-LetF) assignment rule. elif (stmts[1].__class__ is ast.FunctionDef and len(stmts[0].targets) == 1 and stmts[0].t.is_arrow() and stmts[0].targets[0].id == stmts[1].name): tdec = stmts[0] tar_id = tdec.targets[0].id fndef = stmts[1] # Throw an error if the typedec target has already been declared with a # different type. try: tar_t = env_get(env, tar_id) if tar_t != tdec.t: raise TypeMultiSpecifiedError() except TypeUnspecifiedError: pass env1, env2 = dict(env), dict(env) env1[tar_id] = tdec.t env2[tar_id] = tdec.t.quantify() return check_stmt(fndef, env1) and check_stmt_list(stmts[2:], env2) # (StmtsT) assignment rule. else: tdec = stmts[0] # Throw an error if a typedec target has already been declared with a # different type. for tar in tdec.targets: try: tar_t = env_get(env, tar.id) if tar_t != tdec.t: raise TypeMultiSpecifiedError() except TypeUnspecifiedError: pass new_env = dict(env) for tar in tdec.targets: new_env[tar.id] = tdec.t return check_stmt_list(stmts[1:], new_env) # No assignment rule found. return False