diff --git a/13/ast.cpp b/13/ast.cpp index 1f1eb31..01b7413 100644 --- a/13/ast.cpp +++ b/13/ast.cpp @@ -235,13 +235,13 @@ struct case_mappings { std::vector& make_case_for(tag_type tag) { if(default_case) - throw type_error("attempted pattern match after catch-all"); + throw compiler_error("attempted pattern match after catch-all"); return defined_cases[tag]; } std::vector& make_default_case() { if(default_case) - throw type_error("attempted repeated use of catch-all"); + throw compiler_error("attempted repeated use of catch-all"); default_case.emplace(std::vector()); return *default_case; } @@ -285,7 +285,7 @@ struct case_strategy_bool { if(!(cpat = dynamic_cast(pt.get())) || (cpat->constr != "True" && cpat->constr != "False") || cpat->params.size() != 0) - throw type_error( + throw compiler_error( "pattern cannot be converted to a boolean", pt->loc); return cpat->constr == "True"; @@ -335,7 +335,7 @@ struct case_strategy_data { repr_type repr_from_pattern(const pattern_ptr& pt) { pattern_constr* cpat; if(!(cpat = dynamic_cast(pt.get()))) - throw type_error( + throw compiler_error( "pattern cannot be interpreted as constructor.", pt->loc); return std::make_pair( @@ -398,7 +398,7 @@ void compile_case(const ast_case& node, const env_ptr& env, const type* type, st pattern_var* vpat; if((vpat = dynamic_cast(branch->pat.get()))) { if(cases.defined_cases_count() == strategy.case_count()) - throw type_error("redundant catch-all pattern", branch->pat->loc); + throw compiler_error("redundant catch-all pattern", branch->pat->loc); auto& branch_into = cases.make_default_case(); env_ptr new_env(new env_var(vpat->var, env)); branch->expr->compile(new_env, branch_into); @@ -412,7 +412,7 @@ void compile_case(const ast_case& node, const env_ptr& env, const type* type, st if(!(cases.defined_cases_count() == strategy.case_count() || cases.default_case_defined())) - throw type_error("incomplete patterns", node.loc); + throw compiler_error("incomplete patterns", node.loc); strategy.into_instructions(cases, into); } diff --git a/13/definition.cpp b/13/definition.cpp index 0a92dcf..8ccbd55 100644 --- a/13/definition.cpp +++ b/13/definition.cpp @@ -64,9 +64,9 @@ void definition_data::insert_constructors() const { type_ptr return_type(return_app); for(auto& var : vars) { if(var_set.find(var) != var_set.end()) - throw std::runtime_error( + throw compiler_error( std::string("type variable ") + - var + std::string(" used twice in data type definition.")); + var + std::string(" used twice in data type definition."), loc); var_set.insert(var); return_app->arguments.push_back(type_ptr(new type_var(var))); } diff --git a/13/error.cpp b/13/error.cpp index b26c7e7..06c83c3 100644 --- a/13/error.cpp +++ b/13/error.cpp @@ -1,19 +1,32 @@ #include "error.hpp" +const char* compiler_error::what() const noexcept { + return "an error occured while compiling the program"; +} + +void compiler_error::print_about(std::ostream& to) { + to << what() << ": "; + to << description << std::endl; +} + +void compiler_error::print_location(std::ostream& to, parse_driver& drv, bool highlight) { + if(!loc) return; + to << "occuring on line " << loc->begin.line << ":" << std::endl; + drv.print_location(to, *loc, highlight); +} + +void compiler_error::pretty_print(std::ostream& to, parse_driver& drv) { + print_about(to); + print_location(to, drv); +} + const char* type_error::what() const noexcept { return "an error occured while checking the types of the program"; } void type_error::pretty_print(std::ostream& to, parse_driver& drv) { - to << "encountered error while typechecking program: "; - to << description << std::endl; - - if(loc) { - to << "occuring on line " << loc->begin.line << ":" << std::endl; - to << std::endl << "```" << std::endl; - drv.print_highlighted_location(to, *loc); - to << "```" << std::endl << std::endl; - } + print_about(to); + print_location(to, drv, true); } void unification_error::pretty_print(std::ostream& to, parse_driver& drv, type_mgr& mgr) { diff --git a/13/error.hpp b/13/error.hpp index 0cf51d5..c76df13 100644 --- a/13/error.hpp +++ b/13/error.hpp @@ -7,12 +7,26 @@ using maybe_location = std::optional; -struct type_error : std::exception { +struct compiler_error : std::exception { std::string description; + maybe_location loc; + + compiler_error(std::string d, maybe_location l = std::nullopt) + : description(std::move(d)), loc(std::move(l)) {} + + const char* what() const noexcept override; + + void print_about(std::ostream& to); + void print_location(std::ostream& to, parse_driver& drv, bool highlight = false); + + void pretty_print(std::ostream& to, parse_driver& drv); +}; + +struct type_error : compiler_error { std::optional loc; type_error(std::string d, maybe_location l = std::nullopt) - : description(std::move(d)), loc(std::move(l)) {} + : compiler_error(std::move(d), std::move(l)) {} const char* what() const noexcept override; void pretty_print(std::ostream& to, parse_driver& drv); diff --git a/13/main.cpp b/13/main.cpp index 44fe331..188f299 100644 --- a/13/main.cpp +++ b/13/main.cpp @@ -20,7 +20,7 @@ #include "llvm/Target/TargetMachine.h" void yy::parser::error(const yy::location& loc, const std::string& msg) { - std::cout << "An error occured: " << msg << std::endl; + std::cerr << "An error occured: " << msg << std::endl; } void prelude_types(definition_group& defs, type_env_ptr env) { @@ -110,12 +110,12 @@ void output_llvm(llvm_context& ctx, const std::string& filename) { std::error_code ec; llvm::raw_fd_ostream file(filename, ec, llvm::sys::fs::F_None); if (ec) { - throw std::runtime_error("failed to open object file for writing"); + throw compiler_error("failed to open object file for writing"); } else { llvm::CodeGenFileType type = llvm::CGFT_ObjectFile; llvm::legacy::PassManager pm; if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) { - throw std::runtime_error("failed to add passes to pass manager"); + throw compiler_error("failed to add passes to pass manager"); } else { pm.run(ctx.module); file.close(); @@ -177,10 +177,11 @@ void gen_llvm(global_scope& scope) { int main(int argc, char** argv) { if(argc != 2) { std::cerr << "please enter a file to compile." << std::endl; + exit(1); } parse_driver driver(argv[1]); if(!driver.run_parse()) { - std::cerr << "failed to open file " << argv[1] << std::endl; + std::cerr << "failed to parse file " << argv[1] << std::endl; exit(1); } @@ -207,7 +208,7 @@ int main(int argc, char** argv) { err.pretty_print(std::cerr, driver, mgr); } catch(type_error& err) { err.pretty_print(std::cerr, driver); - } catch(std::runtime_error& err) { - std::cerr << err.what() << std::endl; + } catch (compiler_error& err) { + err.pretty_print(std::cerr, driver); } } diff --git a/13/parse_driver.cpp b/13/parse_driver.cpp index 971f844..99193c7 100644 --- a/13/parse_driver.cpp +++ b/13/parse_driver.cpp @@ -5,8 +5,6 @@ bool parse_driver::run_parse() { FILE* stream = fopen(file_name.c_str(), "r"); if(!stream) return false; - string_stream = std::ostringstream(); - file_offset = 0; line_offsets.push_back(0); yyscan_t scanner; yylex_init(&scanner); @@ -29,27 +27,27 @@ void parse_driver::mark_line() { } size_t parse_driver::get_index(int line, int column) { - assert(line > 0); - assert(line <= line_offsets.size()); - size_t file_offset = line_offsets[line-1]; - file_offset += column - 1; - return file_offset; + assert(line > 0 && line <= line_offsets.size()); + return line_offsets[line-1] + column - 1; } size_t parse_driver::get_line_end(int line) { - if(line > line_offsets.size()) return file_contents.size(); + if(line == line_offsets.size()) return file_contents.size(); return get_index(line+1, 1); } -void parse_driver::print_highlighted_location(std::ostream& stream, const yy::location& loc) { +void parse_driver::print_location( + std::ostream& stream, + const yy::location& loc, + bool highlight) { size_t print_start = get_index(loc.begin.line, 1); size_t highlight_start = get_index(loc.begin.line, loc.begin.column); size_t highlight_end = get_index(loc.end.line, loc.end.column); size_t print_end = get_line_end(loc.end.line); const char* content = file_contents.c_str(); stream.write(content + print_start, highlight_start - print_start); - stream << "\033[4;31m"; + if(highlight) stream << "\033[4;31m"; stream.write(content + highlight_start, highlight_end - highlight_start); - stream << "\033[0m"; + if(highlight) stream << "\033[0m"; stream.write(content + highlight_end, print_end - highlight_end); } diff --git a/13/parse_driver.hpp b/13/parse_driver.hpp index 14ffb8d..4f22850 100644 --- a/13/parse_driver.hpp +++ b/13/parse_driver.hpp @@ -14,13 +14,13 @@ void scanner_destroy(yyscan_t* scanner); struct parse_driver { std::string file_name; std::ostringstream string_stream; + std::string file_contents; yy::location location; size_t file_offset; - std::vector line_offsets; + definition_group global_defs; - std::string file_contents; parse_driver(const std::string& file) : file_name(file), file_offset(0) {} @@ -30,7 +30,10 @@ struct parse_driver { void mark_line(); size_t get_index(int line, int column); size_t get_line_end(int line); - void print_highlighted_location(std::ostream& stream, const yy::location& loc); + void print_location( + std::ostream& stream, + const yy::location& loc, + bool highlight = true); }; #define YY_DECL yy::parser::symbol_type yylex(yyscan_t yyscanner, parse_driver& drv)