From b065d958041b6373d1466439df8a8f01469d7710 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Aug 2019 15:34:13 -0700 Subject: [PATCH] Add errors ection to Part 4 of compiler posts --- 04/CMakeLists.txt | 1 + 04/ast.cpp | 20 +++++++++++++------- 04/error.cpp | 5 +++++ 04/error.hpp | 21 +++++++++++++++++++++ 04/main.cpp | 30 ++++++++++++++++++++++-------- 04/type.cpp | 3 ++- 6 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 04/error.cpp create mode 100644 04/error.hpp diff --git a/04/CMakeLists.txt b/04/CMakeLists.txt index cfee544..9d2d571 100644 --- a/04/CMakeLists.txt +++ b/04/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(compiler ast.cpp ast.hpp definition.cpp env.cpp env.hpp type.cpp type.hpp + error.cpp error.hpp ${BISON_parser_OUTPUTS} ${FLEX_scanner_OUTPUTS} main.cpp diff --git a/04/ast.cpp b/04/ast.cpp index b9f920f..f8a88df 100644 --- a/04/ast.cpp +++ b/04/ast.cpp @@ -1,5 +1,6 @@ #include "ast.hpp" #include +#include "error.hpp" std::string op_name(binop op) { switch(op) { @@ -8,7 +9,7 @@ std::string op_name(binop op) { case TIMES: return "*"; case DIVIDE: return "/"; } - throw 0; + return "??"; } 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 rtype = right->typecheck(mgr, env); 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 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 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(); + if(!dynamic_cast(case_type.get())) { + throw type_error("attempting case analysis of non-data type"); + } + for(auto& branch : branches) { type_env new_env = env.scope(); 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 { 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++) { type_arr* arr = dynamic_cast(constructor_type.get()); - if(!arr) throw 0; + if(!arr) throw type_error("too many parameters in constructor pattern"); env.bind(params[i], arr->left); constructor_type = arr->right; } mgr.unify(t, constructor_type); - type_base* result_type = dynamic_cast(constructor_type.get()); - if(!result_type) throw 0; } diff --git a/04/error.cpp b/04/error.cpp new file mode 100644 index 0000000..f5125e3 --- /dev/null +++ b/04/error.cpp @@ -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"; +} diff --git a/04/error.hpp b/04/error.hpp new file mode 100644 index 0000000..5bfbc7e --- /dev/null +++ b/04/error.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#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") {} +}; diff --git a/04/main.cpp b/04/main.cpp index 337bc7c..60dd9c9 100644 --- a/04/main.cpp +++ b/04/main.cpp @@ -1,7 +1,8 @@ #include "ast.hpp" -#include "parser.hpp" -#include "type.hpp" #include +#include "parser.hpp" +#include "error.hpp" +#include "type.hpp" void yy::parser::error(const std::string& msg) { std::cout << "An error occured: " << msg << std::endl; @@ -9,10 +10,9 @@ void yy::parser::error(const std::string& msg) { extern std::vector program; -void typecheck_program(const std::vector& prog) { - type_mgr mgr; - type_env env; - +void typecheck_program( + const std::vector& prog, + type_mgr& mgr, type_env& env) { type_ptr int_type = type_ptr(new type_base("Int")); type_ptr binop_type = type_ptr(new type_arr( int_type, @@ -40,6 +40,9 @@ void typecheck_program(const std::vector& prog) { int main() { yy::parser parser; + type_mgr mgr; + type_env env; + parser.parse(); for(auto& definition : program) { definition_defn* def = dynamic_cast(definition.get()); @@ -51,6 +54,17 @@ int main() { def->body->print(1, std::cout); } - typecheck_program(program); - std::cout << program.size() << std::endl; + try { + 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; + } } diff --git a/04/type.cpp b/04/type.cpp index 8a8e22d..0fc7364 100644 --- a/04/type.cpp +++ b/04/type.cpp @@ -1,6 +1,7 @@ #include "type.hpp" #include #include +#include "error.hpp" void type_var::print(const type_mgr& mgr, std::ostream& to) const { 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; } - throw 0; + throw unification_error(l, r); } void type_mgr::bind(const std::string& s, type_ptr t) {