ErrorReporting.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #include "ErrorReporting.h"
  2. #include <map>
  3. #include <fstream>
  4. #include <sstream>
  5. using qlow::InternalError;
  6. using qlow::CompileError;
  7. using qlow::SyntaxError;
  8. using qlow::SemanticError;
  9. namespace qlow
  10. {
  11. void reportError(const CompileError& ce) noexcept
  12. {
  13. Printer& printer = Printer::getInstance();
  14. ce.print(printer);
  15. }
  16. void reportError(const std::string& msg) noexcept
  17. {
  18. Printer& printer = Printer::getInstance();
  19. printError(printer, msg);
  20. }
  21. void printError(Printer& printer, const std::string& msg) noexcept
  22. {
  23. printer.bold();
  24. printer.foreground(Printer::RED, true);
  25. printer << "error: ";
  26. printer.removeFormatting();
  27. printer << msg << std::endl;
  28. }
  29. void printError(Printer& printer, const std::string& msg, const CodePosition& cp) noexcept
  30. {
  31. printer.bold();
  32. printer << cp.getReportFormat() << ": "; //cp.filename << ":" << cp.first_line << ":" << cp.first_column << ": ";
  33. printer.foreground(Printer::RED, true);
  34. printer << "error: ";
  35. printer.removeFormatting();
  36. printer << msg << std::endl;
  37. }
  38. void printError(ErrorCode ec, Printer& printer) noexcept
  39. {
  40. static const std::map<ErrorCode, std::string> error = {
  41. { ErrorCode::NO_INFILES, "no files were provided" },
  42. };
  43. if (error.find(ec) != error.end())
  44. printError(printer, error.at(ec));
  45. }
  46. }
  47. std::string qlow::CodePosition::getReportFormat(void) const noexcept
  48. {
  49. std::ostringstream s;
  50. s << filename << ":" << first_line << ":" << first_column;
  51. return s.str();
  52. }
  53. void InternalError::print(Printer& printer) const noexcept
  54. {
  55. printError(printer, getMessage());
  56. printer <<
  57. "\n"
  58. "This kind of error isn't supposed to happen.\n\n"
  59. "Please submit a bug report to nicolas.winkler@gmx.ch\n"
  60. ;
  61. }
  62. const std::string& InternalError::getMessage(void) const noexcept
  63. {
  64. using namespace std::literals;
  65. static std::map<ErrorCode, std::string> errors = {
  66. {ErrorCode::OUT_OF_MEMORY, "out of memory"},
  67. {ErrorCode::PARSER_INIT_FAILED, "parser initialization failed"},
  68. {ErrorCode::PARSER_DEST_FAILED, "parser destruction failed"},
  69. {ErrorCode::PARSER_FAILED, "parser failed"},
  70. {ErrorCode::PARSER_FAILED, "invalid type encountered"},
  71. };
  72. if (errors.find(errorCode) != errors.end())
  73. return errors.at(errorCode);
  74. else {
  75. static std::string msg = ""s;
  76. return msg;
  77. }
  78. }
  79. CompileError::~CompileError(void)
  80. {
  81. }
  82. // TODO rewrite more compact and more readable
  83. void CompileError::underlineError(Printer& printer) const noexcept
  84. {
  85. std::ifstream file(where.filename);
  86. if (!file)
  87. return;
  88. if (where.isMultiline()) {
  89. int lineNr = 1;
  90. while (lineNr < where.first_line) {
  91. if (file.get() == '\n') {
  92. lineNr++;
  93. }
  94. }
  95. std::string line;
  96. std::getline(file, line);
  97. int lineNrLength = std::to_string(lineNr).size();
  98. printer << "from here:" << std::endl;
  99. printer.foreground(Printer::Color::YELLOW, true);
  100. printer << lineNr;
  101. printer.removeFormatting();
  102. printer << ": " << line << std::endl;
  103. for (int i = 0; i < where.first_column + lineNrLength + 2; i++) {
  104. printer << ' ';
  105. }
  106. printer.foreground(Printer::Color::RED, true);
  107. for (size_t i = where.first_column; i < line.size(); i++) {
  108. printer << '^';
  109. }
  110. printer.removeFormatting();
  111. lineNr++;
  112. while (lineNr < where.last_line) {
  113. if (file.get() == '\n') {
  114. lineNr++;
  115. }
  116. }
  117. std::getline(file, line);
  118. lineNrLength = std::to_string(lineNr).size();
  119. printer << std::endl << "to here:" << std::endl;
  120. printer.foreground(Printer::Color::YELLOW, true);
  121. printer << lineNr;
  122. printer.removeFormatting();
  123. printer << ": " << line << std::endl;
  124. for (int i = 0; i < lineNrLength + 2; i++) {
  125. printer << ' ';
  126. }
  127. printer.foreground(Printer::Color::RED, true);
  128. for (int i = 0; i < where.last_column; i++) {
  129. printer << '^';
  130. }
  131. printer.removeFormatting();
  132. printer << std::endl;
  133. }
  134. else {
  135. int lineNr = 1;
  136. while (lineNr < where.first_line) {
  137. if (file.get() == '\n') {
  138. lineNr++;
  139. }
  140. }
  141. std::string line;
  142. std::getline(file, line);
  143. printer << line << std::endl;
  144. for (int i = 0; i < where.first_column; i++) {
  145. printer << ' ';
  146. }
  147. printer.foreground(Printer::Color::RED, true);
  148. for (int i = where.first_column; i < where.last_column; i++) {
  149. printer << '^';
  150. }
  151. printer.removeFormatting();
  152. printer << std::endl;
  153. }
  154. }
  155. void SyntaxError::print(Printer& printer) const noexcept
  156. {
  157. using namespace std::literals;
  158. if (message == "")
  159. printError(printer, "Syntax error", where);
  160. else
  161. printError(printer, "Syntax error: "s + message, where);
  162. underlineError(printer);
  163. }
  164. void SemanticError::print(Printer& printer) const noexcept
  165. {
  166. std::string errMsg = getMessage();
  167. printError(printer, errMsg + (errMsg != "" ? ": " : "") + message, where);
  168. underlineError(printer);
  169. }
  170. std::string SemanticError::getMessage(void) const noexcept
  171. {
  172. using namespace std::literals;
  173. static const std::map<ErrorCode, std::string> errors = {
  174. {UNKNOWN_TYPE, "unknown type"},
  175. {FEATURE_NOT_FOUND, "method or variable not found"},
  176. {DUPLICATE_CLASS_DEFINITION, "duplicate class definition"},
  177. {DUPLICATE_FIELD_DECLARATION, "duplicate field declaration"},
  178. {DUPLICATE_METHOD_DEFINITION, "duplicate method definition"},
  179. {OPERATOR_NOT_FOUND, ""},
  180. {WRONG_NUMBER_OF_ARGUMENTS, "wrong number of arguments passed"},
  181. {INVALID_RETURN_TYPE, "invalid return type"},
  182. };
  183. if (errors.find(errorCode) != errors.end())
  184. return errors.at(errorCode);
  185. else
  186. return ""s;
  187. }
  188. SemanticError SemanticError::invalidReturnType(const std::string& should,
  189. const std::string& is, const CodePosition& where)
  190. {
  191. return SemanticError{ INVALID_RETURN_TYPE, "return type should be " +
  192. should + ", but " + is + " is given.", where };
  193. }
  194. SemanticError SemanticError::newForNonClass(const std::string& type,
  195. const CodePosition& where)
  196. {
  197. return SemanticError{ NEW_FOR_NON_CLASS, "cannot allocate instance of non-class type '" + type + "' using new", where };
  198. }