2019-08-25 01:36:34 -07:00
|
|
|
#include "ast.hpp"
|
2019-08-26 00:13:10 -07:00
|
|
|
|
|
|
|
std::string op_name(binop op) {
|
|
|
|
switch(op) {
|
|
|
|
case PLUS: return "+";
|
|
|
|
case MINUS: return "-";
|
|
|
|
case TIMES: return "*";
|
|
|
|
case DIVIDE: return "/";
|
|
|
|
}
|
|
|
|
throw 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_int::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
return type_ptr(new type_base("Int"));
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_lid::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
return env.lookup(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_uid::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
return env.lookup(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_binop::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
type_ptr ltype = left->typecheck(mgr, env);
|
|
|
|
type_ptr rtype = right->typecheck(mgr, env);
|
|
|
|
type_ptr ftype = env.lookup(op_name(op));
|
|
|
|
if(!ftype) throw 0;
|
|
|
|
|
|
|
|
type_ptr place_a = mgr.new_type();
|
|
|
|
type_ptr place_b = mgr.new_type();
|
|
|
|
type_ptr place_c = mgr.new_type();
|
|
|
|
type_ptr arrow_one = type_ptr(new type_arr(place_b, place_c));
|
|
|
|
type_ptr arrow_two = type_ptr(new type_arr(place_a, arrow_one));
|
|
|
|
|
|
|
|
mgr.unify(arrow_two, ftype);
|
|
|
|
mgr.unify(place_a, ltype);
|
|
|
|
mgr.unify(place_b, rtype);
|
|
|
|
return place_c;
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_app::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
type_ptr ltype = left->typecheck(mgr, env);
|
|
|
|
type_ptr rtype = right->typecheck(mgr, env);
|
|
|
|
|
|
|
|
type_ptr place_a = mgr.new_type();
|
|
|
|
type_ptr place_b = mgr.new_type();
|
|
|
|
type_ptr arrow = type_ptr(new type_arr(place_a, place_b));
|
|
|
|
mgr.unify(arrow, ltype);
|
|
|
|
mgr.unify(place_a, rtype);
|
|
|
|
return place_b;
|
|
|
|
}
|
|
|
|
|
|
|
|
type_ptr ast_case::typecheck(type_mgr& mgr, const type_env& env) const {
|
|
|
|
type_ptr case_type = of->typecheck(mgr, env);
|
|
|
|
type_ptr branch_type = mgr.new_type();
|
|
|
|
|
|
|
|
for(auto& branch : branches) {
|
|
|
|
type_env new_env = env.scope();
|
|
|
|
branch->pat->match(case_type, mgr, new_env);
|
|
|
|
type_ptr curr_branch_type = branch->expr->typecheck(mgr, new_env);
|
|
|
|
mgr.unify(branch_type, curr_branch_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
return branch_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pattern_var::match(type_ptr t, type_mgr& mgr, type_env& env) const {
|
|
|
|
env.bind(var, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pattern_constr::match(type_ptr t, type_mgr& mgr, type_env& env) const {
|
|
|
|
type_ptr constructor_type = env.lookup(constr);
|
|
|
|
if(!constructor_type) throw 0;
|
|
|
|
|
|
|
|
for(int i = 0; i < params.size(); i++) {
|
|
|
|
type_arr* arr = dynamic_cast<type_arr*>(constructor_type.get());
|
|
|
|
if(!arr) throw 0;
|
|
|
|
|
|
|
|
env.bind(params[i], arr->left);
|
|
|
|
constructor_type = arr->right;
|
|
|
|
}
|
|
|
|
|
|
|
|
mgr.unify(t, constructor_type);
|
|
|
|
type_base* result_type = dynamic_cast<type_base*>(constructor_type.get());
|
|
|
|
if(!result_type) throw 0;
|
|
|
|
}
|