From 2860e570daa8eb2a3c629514bd266abe013056ce Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Tue, 8 Mar 2022 13:19:34 +0000 Subject: [PATCH] Refactor the error-backend and setup the test file for it --- dev.org | 4 + libserene/include/serene/environment.h | 5 +- libserene/include/serene/errors.h | 8 +- libserene/include/serene/errors/base.h | 7 +- libserene/lib/errors.cpp | 3 - libserene/tests/context_tests.cpp.inc | 3 + libserene/tests/errors/error_tests.cpp.inc | 34 ++++-- libserene/tests/serenetests.cpp | 2 +- serene-tblgen/serene/errors-backend.cpp | 114 ++++++++++----------- 9 files changed, 100 insertions(+), 80 deletions(-) diff --git a/dev.org b/dev.org index dd23eb5..8333031 100644 --- a/dev.org +++ b/dev.org @@ -127,6 +127,10 @@ and recompile those functions with more optimization passes * TODOs +** TODO Investigate possible implementanion for Internal Errors +- An option is to use llvm registry functionality like the one used in =clang-doc= instead of + =errorVariants= var. + ** TODO In =SereneContext::getLatestJITDylib= function, make sure that the JITDylib is still valid Make sure that the returning Dylib still exists in the JIT by calling =jit->engine->getJITDylibByName(dylib_name);= diff --git a/libserene/include/serene/environment.h b/libserene/include/serene/environment.h index 144354d..70baa81 100644 --- a/libserene/include/serene/environment.h +++ b/libserene/include/serene/environment.h @@ -16,10 +16,9 @@ * along with this program. If not, see . */ -#ifndef SERENE_ENVIRONMENT_H -#define SERENE_ENVIRONMENT_H +#ifndef SERENE_TEST_ENVIRONMENT_H +#define SERENE_TEST_ENVIRONMENT_H -#include "serene/llvm/patches.h" #include "serene/utils.h" #include diff --git a/libserene/include/serene/errors.h b/libserene/include/serene/errors.h index ce93741..1afb07e 100644 --- a/libserene/include/serene/errors.h +++ b/libserene/include/serene/errors.h @@ -22,6 +22,8 @@ #include "serene/errors/base.h" #include "serene/errors/errc.h" +#include + #define GET_CLASS_DEFS #include "serene/errors/errs.h.inc" @@ -29,8 +31,12 @@ namespace serene::errors { +/// Create and return a Serene flavored `llvm::Error` by passing the parameters +/// directly to the constructor of type `E`. +/// +/// This is the official way of creating error objects in Serene. template -llvm::Error makeError(Args &&...args) { +SERENE_EXPORT llvm::Error makeError(Args &&...args) { return llvm::make_error(std::forward(args)...); }; diff --git a/libserene/include/serene/errors/base.h b/libserene/include/serene/errors/base.h index 8ed7f6e..2358152 100644 --- a/libserene/include/serene/errors/base.h +++ b/libserene/include/serene/errors/base.h @@ -28,19 +28,20 @@ namespace serene::errors { +// This class is used in the generated code struct ErrorVariant { - int id; + const int id; const std::string title; const std::string desc; const std::string help; - static ErrorVariant make(int id, const char *t, const char *d, + static ErrorVariant make(const int id, const char *t, const char *d, const char *h) { return ErrorVariant(id, t, d, h); }; private: - ErrorVariant(int id, const char *t, const char *d, const char *h) + ErrorVariant(const int id, const char *t, const char *d, const char *h) : id(id), title(t), desc(d), help(h){}; }; diff --git a/libserene/lib/errors.cpp b/libserene/lib/errors.cpp index 7bfb922..70f0c93 100644 --- a/libserene/lib/errors.cpp +++ b/libserene/lib/errors.cpp @@ -17,6 +17,3 @@ */ #include "serene/errors.h" - -#define GET_ERRS_ARRAY -#include "serene/errors/errs.h.inc" diff --git a/libserene/tests/context_tests.cpp.inc b/libserene/tests/context_tests.cpp.inc index 6a10925..0e4ba8f 100644 --- a/libserene/tests/context_tests.cpp.inc +++ b/libserene/tests/context_tests.cpp.inc @@ -21,6 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#ifndef SERENE_TEST_CONTEXT_H +#define SERENE_TEST_CONTEXT_H #include "serene/context.h" #include "serene/namespace.h" @@ -162,3 +164,4 @@ TEST_CASE("context and jit", "[context]") { }; } // namespace serene +#endif diff --git a/libserene/tests/errors/error_tests.cpp.inc b/libserene/tests/errors/error_tests.cpp.inc index bbb2828..47c4bb3 100644 --- a/libserene/tests/errors/error_tests.cpp.inc +++ b/libserene/tests/errors/error_tests.cpp.inc @@ -22,25 +22,37 @@ * SOFTWARE. */ +#ifndef SERENE_TEST_ERRORS_H +#define SERENE_TEST_ERRORS_H + #include "serene/errors.h" -#include "serene/exprs/symbol.h" -#include "../test_helpers.cpp.inc" -#include +#include -#include +#include +#include +#include namespace serene { namespace errors { -TEST_CASE("Error Expression", "[expression]") { - std::unique_ptr range(dummyLocation()); - auto err = exprs::makeAndCast(*range.get(), &DefExpectSymbol, - "Something Failed"); +TEST_CASE("Serene Error construction", "[errors]") { + { + std::unique_ptr range(dummyLocation()); + llvm::Error err = llvm::make_error(*range, "test error"); - CHECK(err->getVariant()->id == E0001); - CHECK(err->toString() == ""); -}; + auto unhandled = + llvm::handleErrors(std::move(err), [&](const PassFailureError &e) { + REQUIRE(e.message() == "test error"); + CHECK(errorVariants[e.ID].title == "PassFailureError"); + CHECK(errorVariants[e.ID].desc == "Pass Failure."); + CHECK(errorVariants[e.ID].help.empty()); + }); + CHECK(!unhandled); + }; } // namespace errors +}; // namespace errors } // namespace serene + +#endif diff --git a/libserene/tests/serenetests.cpp b/libserene/tests/serenetests.cpp index cf4265e..8b61e95 100644 --- a/libserene/tests/serenetests.cpp +++ b/libserene/tests/serenetests.cpp @@ -19,8 +19,8 @@ #define CATCH_CONFIG_MAIN #include "./context_tests.cpp.inc" #include "./environment_tests.cpp.inc" +#include "./errors/error_tests.cpp.inc" #include "./setup.cpp.inc" -// #include "./errors/error_tests.cpp.inc" // #include "./exprs/expression_tests.cpp.inc" // #include "./exprs/list_tests.cpp.inc" // #include "./exprs/number_tests.cpp.inc" diff --git a/serene-tblgen/serene/errors-backend.cpp b/serene-tblgen/serene/errors-backend.cpp index 129e03e..ac7496d 100644 --- a/serene-tblgen/serene/errors-backend.cpp +++ b/serene-tblgen/serene/errors-backend.cpp @@ -16,6 +16,14 @@ * along with this program. If not, see . */ +/** + * Commentary: + * This is a `tablegen` backend to read from generate error definitions + * from the given tablegen records defined in a `.td` file. It relies on + * Two main classes to be available in the target source code. `SereneError` + * and `ErrorVariant`. Checkout `libserene/include/serene/errors/base.h`. + */ + // The "serene/" part is due to a convention that we use in the project #include "serene/errors-backend.h" @@ -65,48 +73,7 @@ void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec, << "public:\n" << " using llvm::ErrorInfo<" << recName << ", " << "SereneError>::ErrorInfo;\n" - << " constexpr static const int ID = " << id << ";\n};\n\n" - << "static const ErrorVariant " << recName << INSTANCE_SUFFIX - << " = ErrorVariant::make(\n" - << " " << id << ",\n" - << " \"" << recName << "\",\n"; - - auto desc = defRec.getValueAsString("desc"); - - if (desc.empty()) { - llvm::PrintError("'desc' field is empty for " + recName); - } - - os << " \"" << desc << "\",\n"; - - auto help = defRec.getValueAsString("help"); - - if (!help.empty()) { - - const llvm::MemoryBufferRef value(help, "help"); - - llvm::line_iterator lines(value, false); - while (!lines.is_at_end()) { - if (lines.line_number() != 1) { - os << '\t'; - } - auto prevLine = *lines; - lines++; - os << '"' << prevLine << '"'; - - if (lines.is_at_end()) { - os << ";\n"; - } else { - os << '\n'; - } - } - } else { - os << " \"\""; - } - - os << ");\n"; - // os << " " << help << ");\n"; - // auto *stringVal = llvm::dyn_cast(val.getValue()); + << " constexpr static const int ID = " << id << ";\n};\n\n"; }; void ErrorsBackend::createNSBody(llvm::raw_ostream &os) { @@ -135,41 +102,72 @@ void ErrorsBackend::createNSBody(llvm::raw_ostream &os) { createErrorClass(i, *defRec, os); } - }); - os << "#undef GET_CLASS_DEFS\n#endif\n\n"; + os << "static const ErrorVariant errorVariants[" << indexList->size() + << "] = {\n"; - os << "#ifdef GET_ERRS_ARRAY\n\n"; - inNamespace("serene::errors", os, [&](llvm::raw_ostream &os) { - os << "SereneError::ID = -1;\n"; - for (size_t i = 0; i < indexList->size(); i++) { - llvm::Record *defRec = indexList->getElementAsRecord(i); - os << defRec->getName() << "::ID = " << i << ";\n"; - } - - os << "static const std::array " - "variants{\n"; for (size_t i = 0; i < indexList->size(); i++) { llvm::Record *defRec = indexList->getElementAsRecord(i); + auto recName = defRec->getName(); if (!defRec->isSubClassOf("Error")) { continue; } - os << " &" << defRec->getName() << INSTANCE_SUFFIX << ",\n"; + + os << " ErrorVariant::make(" << i << ", \n"; + os << " \"" << recName << "\",\n"; + + auto desc = defRec->getValueAsString("desc"); + + if (desc.empty()) { + llvm::PrintError("'desc' field is empty for " + recName); + } + + os << " \"" << desc << "\",\n"; + + auto help = defRec->getValueAsString("help"); + + if (!help.empty()) { + + const llvm::MemoryBufferRef value(help, "help"); + + llvm::line_iterator lines(value, false); + while (!lines.is_at_end()) { + if (lines.line_number() != 1) { + os << '\t'; + } + auto prevLine = *lines; + lines++; + os << '"' << prevLine << '"'; + + if (lines.is_at_end()) { + os << ";\n"; + } else { + os << '\n'; + } + } + } else { + os << " \"\""; + } + + os << "),\n"; } + + os << "};\n"; }); - os << "\n};\n#undef GET_ERRS_ARRAY\n#endif\n"; + + os << "#undef GET_CLASS_DEFS\n#endif\n\n"; } void ErrorsBackend::run(llvm::raw_ostream &os) { (void)records; llvm::emitSourceFileHeader("Serene's Errors collection", os); + // DO NOT GUARD THE HEADER WITH #ifndef ... os << "#include \"serene/errors/base.h\"\n\n#include " "\n\n"; - os << "#ifndef SERENE_ERRORS_ERRORS_H\n#define SERENE_ERRORS_ERRORS_H\n\n"; + createNSBody(os); - os << "#endif\n"; } void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) {