def let(module, is_rec, seq, body): clc = module.clc with clc.resume_scope(): outer_scope = clc.scope = clc.scope.sub_scope() types = [] for loc, name, annotation, _ in seq: if annotation: type_bind = Typing(clc).eval(annotation) else: type_bind = new_var(clc, name) types.append(type_bind) if is_rec: _, name = sexpr.unloc(name) sym_bind = outer_scope.enter(name) tenv[sym_bind] = type_bind block = [] syms = [] for (loc, name, annotation, bound), sym_type in zip(seq, types): _, name = sexpr.unloc(name) level = tc_state.push_level() inner_scope = clc.scope = outer_scope.sub_scope() if is_rec: sym_bind = inner_scope.require(name) else: sym_bind = inner_scope.enter(name) tenv[sym_bind] = sym_type syms.append(sym_bind) t_inst = te.fresh(tc_state.new_var, sym_type) t_inst = inst(t_inst, rigid=True)[1] bound = module.eval_with_implicit(bound) tc_state.unify(t_inst, bound.type) gen_type = generalise_type(tc_state, t_inst, loc=loc, filename=clc.filename, level=level) bound.type = gen_type unify(gen_type, sym_type) block.append(ignore(ir.Set(sym_bind, bound))) # level = tc_state.push_level() clc.scope = inner_scope.sub_scope() body = module.eval(body) # block.append(body) # body.type = generalise_type(tc_state, body.type, loc=clc.location, filename=clc.filename, level=level) return ir.Expr(type=body.type, expr=ir.Block(block))
def lam(module, arg, type, ret): loc, name = sexpr.unloc(arg) clc = module.clc outer_scope = clc.scope filename = clc.filename path = clc.path if type: type_arg = tc_state.infer(Typing(clc).eval(type)) else: type_arg = new_var(clc, name) with clc.resume_scope(): # level = tc_state.push_level() inner_scope = outer_scope.sub_scope(hold_bound=True) clc.scope = inner_scope sym_arg = inner_scope.enter(name) tenv[sym_arg] = type_arg ret = module.eval(ret) lam_type = te.Arrow( type_arg, ret.type ) # lam_type = generalise_type(tc_state, lam_type, loc=loc, filename=filename, level=level) name = "{} |{}|".format(path, name) sym_arg = ir.Fun(name, filename, sym_arg, ret) return ir.Expr(type=lam_type, expr=sym_arg)
def record(module, pairs, row): _, pairs = sexpr.unloc(pairs) if row: row_t = te.RowPoly(module.eval(row)) else: row_t = te.empty_row fields = [(k, module.eval(v)) for k, v in pairs] row_t = te.row_from_list(fields, row_t) return te.Record(row_t)
def define(self, is_rec, name, annotated, bound): module = Express(self.clc) loc, name = sexpr.unloc(name) clc = self.clc outer_scope = clc.scope if is_rec: sym_def = outer_scope.require(name) else: sym_def = outer_scope.shadow(name) # may shadow with clc.resume_scope(): inner_scope = outer_scope.sub_scope() clc.scope = inner_scope if annotated: t1 = infer(Typing(clc).eval(annotated)) if sym_def in tenv: unify(inst(tenv[sym_def])[1], inst(t1)[1]) else: tenv[sym_def] = t1 else: if sym_def in tenv: t1 = infer(tenv[sym_def]) else: new_var = tc_state.new_var(Var=types.Var, loc=loc, filename=clc.filename, name=sym_def.name) tenv[sym_def] = t1 = new_var level = tc_state.push_level() bound: ir.Expr = module.eval(bound) t1_inst = te.fresh(tc_state.new_var, infer(t1)) t1_inst = inst(t1_inst, rigid=True)[1] t2_inst = bound.type = inst(infer(bound.type))[1] resolve_instance_(outer_scope, bound) unify(t1_inst, t2_inst) bound.type = generalise_type(tc_state, t2_inst, loc=loc, filename=clc.filename, level=level) unify(bound.type, t1) exp_def = ir.Set(sym_def, bound) return ignore(exp_def)
def exist(module, bound_vars: tuple, monotype): bound_vars_ = set(bound_vars) if len(bound_vars) != len(bound_vars_): raise excs.DuplicatedNamedTypeVar(bound_vars_) bound_vars = bound_vars_ filename = module.clc.filename scope = module.clc.scope for n in bound_vars: loc, n = sexpr.unloc(n) sym = scope.enter(n) tvar = tc_state.user_var(Var=types.Var, loc=loc, filename=filename, name=n) tenv[sym] = te.App(types.type_type, tvar) return module.eval(monotype)
def forall(module, unbound_fresh_decls: typing.Tuple[str, ...], polytype): fresh_vars_ = set(unbound_fresh_decls) if len(fresh_vars_) != len(unbound_fresh_decls): raise excs.DuplicatedNamedTypeVar(fresh_vars_) unbound_fresh_decls = fresh_vars_ clc = module.clc forall_scope = types.ForallScope(clc.location, clc.filename) bound_vars = [] with clc.resume_scope(): clc.scope = sub_scope = clc.scope.sub_scope() for n in unbound_fresh_decls: _, n = sexpr.unloc(n) sym = sub_scope.enter(n) bound_var = te.Bound(n, forall_scope) bound_vars.append(bound_var) tenv[sym] = te.App(types.type_type, bound_var) return te.Forall(forall_scope, tuple(bound_vars), module.eval(polytype))
def record(module, pairs, row): clc = module.clc filename = clc.filename location = clc.location level = tc_state.push_level() kv = [] for each in pairs: loc, (attr_name, expr) = sexpr.unloc(each) expr = module.eval_with_implicit(expr) kv.append((attr_name, expr)) kv.sort(key=lambda tp: tp[0]) elts = [elt for _, elt in kv] left = ir.Tuple(elts) fields = [] for k, v in kv: v_type = tc_state.infer(v.type) if isinstance(v_type, te.Forall): v_type = v_type.poly_type fields.append((k, v_type)) if not row: mono = te.Record(te.row_from_list(fields, te.empty_row)) mono = generalise_type(tc_state, mono, level=level, loc=location, filename=filename) return ir.Expr(expr=ir.Tuple( [anyway(left), anyway(ir.Tuple([]))]), type=mono) right = module.eval_with_implicit(row) poly = tc_state.infer( te.Record(te.row_from_list(fields, te.RowPoly(right.type)))) poly = generalise_type(tc_state, poly, level=level, loc=location, filename=filename) return ir.Expr(expr=ir.Merge(left=anyway(left), right=right), type=poly)
def type(module, typename, typedef): clc = module.clc path = clc.path loc, typename = sexpr.unloc(typename) qual_typename = '{}.{}'.format(path, typename) sym_typename = clc.scope.enter(typename) if typedef: # type alias nom_type = tc_state.infer(Typing(clc).eval(typedef)) else: nom_type = types.Nom(qual_typename, loc=loc, filename=clc.filename) tenv[sym_typename] = te.App(types.type_type, nom_type) return wrap_loc( loc, ignore( ir.Set(sym_typename, ir.Expr(type=nom_type, expr=ir.Const(nom_type)))))
def coerce(module, expr): expr = module.eval(expr) loc, _ = sexpr.unloc(expr) return ir.Expr(expr=ir.Coerce(expr), type=new_var(module.clc, "coerce"))
def module(module_eval, is_rec, name, stmts, loc=None): loc, name = sexpr.unloc(name) clc = module_eval.clc scope = clc.scope filename = clc.filename path = clc.path = '.'.join( (*filter(None, clc.path.split('.')), name)) # only for recursive modules. sym_mod: typing.Optional[Sym] = None # generated ir outside module; # only for recursive modules. outer_stmts: typing.List[ir.Expr] = [] # generated ir for module itself inner_stmts: typing.List[ir.Expr] = [] # type of module. will be a non-extensible record. type_mod = None # recursive module. if is_rec: sym_mod = scope.enter(name) new_var = tc_state.new_var(Var=types.Var, loc=loc, filename=filename, name=path) type_mod = tenv[sym_mod] = new_var outer_stmts.append( ignore(ir.Set(sym_mod, ignore(ir.Const(()))))) # for preprocessing # 1. recursive functions and # 2. type definitions. filter_stmts = [] for stmt in stmts: _, stmt_unloc = sexpr.unloc(stmt) # type definition if stmt_unloc[0] is sexpr.type_k: inner_stmts.append(module_eval.eval(stmt)) continue filter_stmts.append(stmt) if stmt_unloc[0] is sexpr.def_k: if stmt_unloc[1]: # Recursive definition. It's guaranteed to # be a function in syntax level. loc, n = sexpr.unloc(stmt_unloc[2]) sym = scope.enter(n) tenv[sym] = tc_state.new_var(Var=types.Var, loc=loc, filename=filename, name=n) for stmt in filter_stmts: inner_stmts.append(module_eval.eval(stmt)) syms = [ sym for sym in scope.get_newest_bounds() if sym is not sym_mod ] row_mod = te.row_from_list([(s.name, tenv[s]) for s in syms], te.empty_row) if type_mod: # recursive module tc_state.unify(type_mod, te.Record(row_mod)) else: type_mod = te.Record(row_mod) elts_mod = [ir.Expr(type=tenv[sym], expr=sym) for sym in syms] elts_mod.sort(key=_sort_sym) val_mod = ir.Expr(type=type_mod, expr=ir.Tuple([ anyway(ir.Tuple(elts_mod)), anyway(ir.Tuple([])) ])) inner_stmts.append(val_mod) exp_mod = ir.Expr(type=type_mod, expr=ir.Block(inner_stmts)) if not is_rec: return exp_mod outer_stmts.append(ignore(ir.Set(sym_mod, exp_mod))) outer_stmts.append(ir.Expr(type=type_mod, expr=sym_mod)) return ir.Expr(type=type_mod, expr=ir.Block(outer_stmts))