74 lines
2.7 KiB
C++
74 lines
2.7 KiB
C++
#include "ast.hpp"
|
|
#include "type_checker.hpp"
|
|
#include "error.hpp"
|
|
|
|
namespace lily {
|
|
type* ast_num::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
std::cout << "checking number" << std::endl;
|
|
return mgr.require_type("Int");
|
|
}
|
|
|
|
type* ast_var::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
std::cout << "checking variable" << std::endl;
|
|
return env->get_identifier_type(name);
|
|
}
|
|
|
|
type* ast_app::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
std::cout << "checking application" << std::endl;
|
|
type* ltype = left->check(mgr, env);
|
|
type* rtype = right->check(mgr, env);
|
|
|
|
// We LHS has to be a function, so unify LHS with that.
|
|
type_func* f = mgr.create_type<type_func>(nullptr, nullptr);
|
|
// Input type of function is known - it's rtype.
|
|
f->left = rtype;
|
|
// Output is not known - create parameter for it.
|
|
type* new_param = mgr.create_type<type_parameter>();
|
|
f->right = new_param;
|
|
|
|
// Unify ltype with the function (we know it has to be one!)
|
|
if(!ltype->unify_with(f))
|
|
throw error("unable to unify application type");
|
|
|
|
return new_param;
|
|
}
|
|
|
|
type* ast_op::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
type* ltype = left->check(mgr, env);
|
|
type* rtype = right->check(mgr, env);
|
|
|
|
// We know the thing has to be a nunmber, so we unify with number type.
|
|
type* inttype = mgr.require_type("Int");
|
|
if(!ltype->unify_with(inttype))
|
|
throw error("left hand side of operator must be a number.");
|
|
if(!rtype->unify_with(inttype))
|
|
throw error("right hand side of operator must be a number.");
|
|
|
|
// We return an integer.
|
|
return inttype;
|
|
}
|
|
|
|
type* ast_let::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
if(env->identifier_exists(name))
|
|
throw error("invalid redefinition of variable.");
|
|
type* etype = expr->check(mgr, env);
|
|
auto new_env = env->with_type(name, etype);
|
|
return in->check(mgr, new_env);
|
|
}
|
|
|
|
type* ast_letrec::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
if(env->identifier_exists(name))
|
|
throw error("invalid redefinition of variable.");
|
|
type* variable_type = mgr.create_type<type_parameter>();
|
|
auto new_env = env->with_type(name, variable_type);
|
|
type* etype = expr->check(mgr, new_env);
|
|
if(!variable_type->unify_with(etype))
|
|
throw error("incompatible type for variable");
|
|
return in->check(mgr, new_env);
|
|
}
|
|
|
|
type* ast_case::check(type_manager& mgr, std::shared_ptr<type_env> env) {
|
|
throw error("unimplemented");
|
|
}
|
|
}
|