Add errors ection to Part 4 of compiler posts

This commit is contained in:
Danila Fedorin 2019-08-28 15:34:13 -07:00
parent 2dd81cf07a
commit b065d95804
6 changed files with 64 additions and 16 deletions

View File

@ -16,6 +16,7 @@ add_executable(compiler
ast.cpp ast.hpp definition.cpp ast.cpp ast.hpp definition.cpp
env.cpp env.hpp env.cpp env.hpp
type.cpp type.hpp type.cpp type.hpp
error.cpp error.hpp
${BISON_parser_OUTPUTS} ${BISON_parser_OUTPUTS}
${FLEX_scanner_OUTPUTS} ${FLEX_scanner_OUTPUTS}
main.cpp main.cpp

View File

@ -1,5 +1,6 @@
#include "ast.hpp" #include "ast.hpp"
#include <ostream> #include <ostream>
#include "error.hpp"
std::string op_name(binop op) { std::string op_name(binop op) {
switch(op) { switch(op) {
@ -8,7 +9,7 @@ std::string op_name(binop op) {
case TIMES: return "*"; case TIMES: return "*";
case DIVIDE: return "/"; case DIVIDE: return "/";
} }
throw 0; return "??";
} }
void print_indent(int n, std::ostream& to) { void print_indent(int n, std::ostream& to) {
@ -53,7 +54,7 @@ type_ptr ast_binop::typecheck(type_mgr& mgr, const type_env& env) const {
type_ptr ltype = left->typecheck(mgr, env); type_ptr ltype = left->typecheck(mgr, env);
type_ptr rtype = right->typecheck(mgr, env); type_ptr rtype = right->typecheck(mgr, env);
type_ptr ftype = env.lookup(op_name(op)); type_ptr ftype = env.lookup(op_name(op));
if(!ftype) throw 0; if(!ftype) throw type_error(std::string("unknown binary operator ") + op_name(op));
type_ptr return_type = mgr.new_type(); type_ptr return_type = mgr.new_type();
type_ptr arrow_one = type_ptr(new type_arr(rtype, return_type)); type_ptr arrow_one = type_ptr(new type_arr(rtype, return_type));
@ -92,9 +93,14 @@ void ast_case::print(int indent, std::ostream& to) const {
} }
type_ptr ast_case::typecheck(type_mgr& mgr, const type_env& env) const { type_ptr ast_case::typecheck(type_mgr& mgr, const type_env& env) const {
type_ptr case_type = of->typecheck(mgr, env); type_var* var;
type_ptr case_type = mgr.resolve(of->typecheck(mgr, env), var);
type_ptr branch_type = mgr.new_type(); type_ptr branch_type = mgr.new_type();
if(!dynamic_cast<type_base*>(case_type.get())) {
throw type_error("attempting case analysis of non-data type");
}
for(auto& branch : branches) { for(auto& branch : branches) {
type_env new_env = env.scope(); type_env new_env = env.scope();
branch->pat->match(case_type, mgr, new_env); branch->pat->match(case_type, mgr, new_env);
@ -122,17 +128,17 @@ void pattern_constr::print(std::ostream& to) const {
void pattern_constr::match(type_ptr t, type_mgr& mgr, type_env& env) const { void pattern_constr::match(type_ptr t, type_mgr& mgr, type_env& env) const {
type_ptr constructor_type = env.lookup(constr); type_ptr constructor_type = env.lookup(constr);
if(!constructor_type) throw 0; if(!constructor_type) {
throw type_error(std::string("pattern using unknown constructor ") + constr);
}
for(int i = 0; i < params.size(); i++) { for(int i = 0; i < params.size(); i++) {
type_arr* arr = dynamic_cast<type_arr*>(constructor_type.get()); type_arr* arr = dynamic_cast<type_arr*>(constructor_type.get());
if(!arr) throw 0; if(!arr) throw type_error("too many parameters in constructor pattern");
env.bind(params[i], arr->left); env.bind(params[i], arr->left);
constructor_type = arr->right; constructor_type = arr->right;
} }
mgr.unify(t, constructor_type); mgr.unify(t, constructor_type);
type_base* result_type = dynamic_cast<type_base*>(constructor_type.get());
if(!result_type) throw 0;
} }

5
04/error.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "error.hpp"
const char* type_error::what() const noexcept {
return "an error occured while checking the types of the program";
}

21
04/error.hpp Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <exception>
#include "type.hpp"
struct type_error : std::exception {
std::string description;
type_error(std::string d)
: description(std::move(d)) {}
const char* what() const noexcept override;
};
struct unification_error : public type_error {
type_ptr left;
type_ptr right;
unification_error(type_ptr l, type_ptr r)
: left(std::move(l)), right(std::move(r)),
type_error("failed to unify types") {}
};

View File

@ -1,7 +1,8 @@
#include "ast.hpp" #include "ast.hpp"
#include "parser.hpp"
#include "type.hpp"
#include <iostream> #include <iostream>
#include "parser.hpp"
#include "error.hpp"
#include "type.hpp"
void yy::parser::error(const std::string& msg) { void yy::parser::error(const std::string& msg) {
std::cout << "An error occured: " << msg << std::endl; std::cout << "An error occured: " << msg << std::endl;
@ -9,10 +10,9 @@ void yy::parser::error(const std::string& msg) {
extern std::vector<definition_ptr> program; extern std::vector<definition_ptr> program;
void typecheck_program(const std::vector<definition_ptr>& prog) { void typecheck_program(
type_mgr mgr; const std::vector<definition_ptr>& prog,
type_env env; type_mgr& mgr, type_env& env) {
type_ptr int_type = type_ptr(new type_base("Int")); type_ptr int_type = type_ptr(new type_base("Int"));
type_ptr binop_type = type_ptr(new type_arr( type_ptr binop_type = type_ptr(new type_arr(
int_type, int_type,
@ -40,6 +40,9 @@ void typecheck_program(const std::vector<definition_ptr>& prog) {
int main() { int main() {
yy::parser parser; yy::parser parser;
type_mgr mgr;
type_env env;
parser.parse(); parser.parse();
for(auto& definition : program) { for(auto& definition : program) {
definition_defn* def = dynamic_cast<definition_defn*>(definition.get()); definition_defn* def = dynamic_cast<definition_defn*>(definition.get());
@ -51,6 +54,17 @@ int main() {
def->body->print(1, std::cout); def->body->print(1, std::cout);
} }
typecheck_program(program); try {
std::cout << program.size() << std::endl; typecheck_program(program, mgr, env);
} catch(unification_error& err) {
std::cout << "failed to unify types: " << std::endl;
std::cout << " (1) \033[34m";
err.left->print(mgr, std::cout);
std::cout << "\033[0m" << std::endl;
std::cout << " (2) \033[32m";
err.right->print(mgr, std::cout);
std::cout << "\033[0m" << std::endl;
} catch(type_error& err) {
std::cout << "failed to type check program: " << err.description << std::endl;
}
} }

View File

@ -1,6 +1,7 @@
#include "type.hpp" #include "type.hpp"
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include "error.hpp"
void type_var::print(const type_mgr& mgr, std::ostream& to) const { void type_var::print(const type_mgr& mgr, std::ostream& to) const {
auto it = mgr.types.find(name); auto it = mgr.types.find(name);
@ -87,7 +88,7 @@ void type_mgr::unify(type_ptr l, type_ptr r) {
if(lid->name == rid->name) return; if(lid->name == rid->name) return;
} }
throw 0; throw unification_error(l, r);
} }
void type_mgr::bind(const std::string& s, type_ptr t) { void type_mgr::bind(const std::string& s, type_ptr t) {