def quote(module, contents): clc = module.clc quotation = Quote(clc) quote_expr = quotation.eval(contents) quote_scope: Scope = quotation.clc.scope sym_arg = quote_scope.enter(".external") name_var = new_var(clc, name="external") tenv[sym_arg] = name_var record_fields = [] for attr_name, each in quote_scope.freevars.items(): record_fields.append((each, attr_name, tenv[each])) rho_group = types.ForallScope(clc.location, filename=clc.filename) rho = te.Bound('ρ', rho_group) type_arg = te.Record( te.row_from_list([(attr, t) for _, attr, t in record_fields], te.RowPoly(rho))) tc_state.unify(name_var, type_arg) exp_arg = ir.Expr(type=tc_state.infer(type_arg), expr=sym_arg) block = [ ignore( ir.Set( each, ir.Expr(type=t, expr=ir.Field(base=exp_arg, attr=attr)))) for each, attr, t in record_fields ] block.append(quote_expr) ret_expr = ir.Fun( "<quote>", clc.filename, sym_arg, ir.Expr(expr=ir.Block(block), type=quote_expr.type)) ret_type = te.Arrow(type_arg, quote_expr.type) ret_type = te.Forall(rho_group, (rho, ), ret_type) return ir.Expr(expr=ret_expr, type=ret_type)
def call(module, f, arg): clc = module.clc f = module.eval(f) f.type = infer(f.type) to_mono = None to_poly = None func_type = f.type # row polymorphisms while isinstance(func_type, te.Implicit): func_type = func_type.type if isinstance(func_type, te.Arrow): # layout of record might change correspondingly. to_mono = func_type.ret to_poly = func_type.arg f.type = inst(f.type)[1] resolve_instance_(clc.scope, f) level = tc_state.push_level() arg = module.eval(arg) arg.type = infer(arg.type) arg_is_forall = isinstance(arg.type, te.Forall) arg.type = inst(arg.type)[1] resolve_instance_(clc.scope, arg) f.type = infer(f.type) if arg_is_forall and isinstance(f.type, te.Arrow) and isinstance( f.type.arg, te.Forall): # a simple strategy to support higher rank types when annotated. f_type_arg = inst(f.type.arg, rigid=True)[1] unify(arg.type, f_type_arg) ret_t = f.type.ret else: ret_t = new_var(clc, name='ret') inst_arrow = te.Arrow(arg.type, ret_t) unify(inst_arrow, f.type) ret_t = generalise_type(tc_state, ret_t, loc=clc.location, filename=clc.filename, level=level) if to_poly: arg = ir.Expr(type=arg.type, expr=ir.Polymorphization(layout_type=to_poly, expr=arg)) ret = ir.Expr(type=ret_t, expr=ir.Invoke(f, arg)) if to_mono: ret = ir.Expr(type=ret_t, expr=ir.Momomorphization(layout_type=to_mono, expr=ret)) return ret
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 tuple(module, elts): if not elts: return ir.Expr(expr=ir.Const(()), type=types.unit_t) if len(elts) is 1: ret = module.eval(elts[0]) return ret level = tc_state.push_level() elts = list(map(module.eval_with_implicit, elts)) type = te.Tuple(tuple(e.type for e in elts)) loc = module.clc.location filename = module.clc.filename type = generalise_type(tc_state, type, loc=loc, filename=filename, level=level) return ir.Expr(expr=ir.Tuple(elts), type=type)
def _resolve_instance_(implicit_types: typing.List[te.T], scope: Scope, expr: ir.Expr): available_syms = list(scope.boundvars.values()) + list( scope.freevars.values()) explicit_type = expr.type implicit_types.reverse() for implicit_t in implicit_types: instanced = ir.Expr(type=explicit_type, expr=expr.expr) expr.expr = ir.Instance(implicit_t, available_syms, instanced)
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 ite(module, cond, true_clause, else_clause): # level = tc_state.push_level() cond = module.eval_with_implicit(cond) tc_state.unify(cond.type, types.bool_t) tc = module.eval_with_implicit(true_clause) ec = module.eval_with_implicit(else_clause) tc_state.unify(tc.type, ec.type) # clc = module.clc # ec.type = tc.type = generalise_type(tc_state, tc.type, level=level, loc=clc.location, filename=clc.filename) return ir.Expr(expr=ir.ITE(cond, tc, ec), type=tc.type)
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 attr(module, base, attr_name: str): # level = tc_state.push_level() base = module.eval_with_implicit(base) clc = module.clc var = new_var(clc, 'attr') tho = new_var(clc, 'ρ') record_type = te.Record( te.row_from_list([(attr_name, var)], te.RowPoly(tho))) # TODO: how to deal with a polymorphic record value? # e.g., forall a. {x : ... | a} unify(record_type, base.type) # var = infer(var) # var = generalise_type(tc_state, var, level=level, loc=clc.location, filename=clc.filename) return ir.Expr(expr=ir.Field(base=base, attr=attr_name), type=var)
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 imp(module, qualname: typing.List[str], *, backend=backend): clc = module.clc name = qualname[-1] sym = clc.scope.enter(name) module_finder = backend.search_module(qualname) if module_finder.exist: sym_mod = module_finder.exist type_mod = type_of_value(sym_mod) exp_mod = ir.Expr(expr=sym_mod, type=type_mod) return ignore(ir.Set(module_finder.exist, exp_mod)) filename, get_code = module_finder.filename, module_finder.get_code path = '.'.join(qualname) new_modular = Modular( CompilerLocalContext(scope=backend.mk_top_scope(), filename=filename, path=path)) ast_mod = parse(get_code(), filename) exp_mod = new_modular.eval(ast_mod) tenv[sym] = exp_mod.type backend.remember_module(path, sym) return ignore(ir.Set(sym, exp_mod))
def wrap_loc(loc: Location, expr: ir.Expr): return ir.Expr(type=expr.type, expr=ir.WrapLoc(loc, expr))
def anyway(x: ir.BaseExpr): return ir.Expr(expr=x, type=types.anyway_type)
def ignore(ex: ir.BaseExpr): return ir.Expr(type=types.unit_t, expr=ex)
} def ignore(ex: ir.BaseExpr): return ir.Expr(type=types.unit_t, expr=ex) def anyway(x: ir.BaseExpr): return ir.Expr(expr=x, type=types.anyway_type) def wrap_loc(loc: Location, expr: ir.Expr): return ir.Expr(type=expr.type, expr=ir.WrapLoc(loc, expr)) unit = ir.Expr(type=types.unit_t, expr=ir.Const(())) ## Compiler contexts class CompilerGlobalContext: tc_state: TCState tenv: typing.Dict[Sym, te.T] backend: 'BackEnd' def __init__(self, tc_state: TCState, tenv: typing.Dict[Sym, te.T], backend: 'BackEnd'): self.tc_state = tc_state self.tenv = tenv self.backend = backend @classmethod
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 literal(module, val): my_type = type_map[type(val)] return ir.Expr(type=my_type, expr=ir.Const(val))
def type(module, name, definition): assert name is None t = Typing(module.clc).eval(definition) return ir.Expr(expr=ir.Const(t), type=te.App(types.type_type, t))
def loc(module, location, contents): module.clc.location = location a = module.eval(contents) return ir.Expr(type=a.type, expr=ir.WrapLoc(location, a))
def extern(module, foreign_code): clc = module.clc return ir.Expr(expr=ir.Extern(foreign_code), type=new_var(clc, 'extern'))
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))
def eval_sym(self, x: str) -> ir.Expr: scope = self.clc.scope my_type = type_of_value(scope.require(x)) var = scope.require(x) return ir.Expr(type=my_type, expr=var)