Refactor the error-backend and setup the test file for it
This commit is contained in:
parent
7d7293aa32
commit
2860e570da
4
dev.org
4
dev.org
|
@ -127,6 +127,10 @@ and recompile those functions with more optimization passes
|
||||||
|
|
||||||
* TODOs
|
* 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
|
** TODO In =SereneContext::getLatestJITDylib= function, make sure that the JITDylib is still valid
|
||||||
Make sure that the returning Dylib still exists in the JIT
|
Make sure that the returning Dylib still exists in the JIT
|
||||||
by calling =jit->engine->getJITDylibByName(dylib_name);=
|
by calling =jit->engine->getJITDylibByName(dylib_name);=
|
||||||
|
|
|
@ -16,10 +16,9 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SERENE_ENVIRONMENT_H
|
#ifndef SERENE_TEST_ENVIRONMENT_H
|
||||||
#define SERENE_ENVIRONMENT_H
|
#define SERENE_TEST_ENVIRONMENT_H
|
||||||
|
|
||||||
#include "serene/llvm/patches.h"
|
|
||||||
#include "serene/utils.h"
|
#include "serene/utils.h"
|
||||||
|
|
||||||
#include <llvm/ADT/StringMap.h>
|
#include <llvm/ADT/StringMap.h>
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "serene/errors/base.h"
|
#include "serene/errors/base.h"
|
||||||
#include "serene/errors/errc.h"
|
#include "serene/errors/errc.h"
|
||||||
|
|
||||||
|
#include <serene/export.h>
|
||||||
|
|
||||||
#define GET_CLASS_DEFS
|
#define GET_CLASS_DEFS
|
||||||
#include "serene/errors/errs.h.inc"
|
#include "serene/errors/errs.h.inc"
|
||||||
|
|
||||||
|
@ -29,8 +31,12 @@
|
||||||
|
|
||||||
namespace serene::errors {
|
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 <typename E, typename... Args>
|
template <typename E, typename... Args>
|
||||||
llvm::Error makeError(Args &&...args) {
|
SERENE_EXPORT llvm::Error makeError(Args &&...args) {
|
||||||
return llvm::make_error<E>(std::forward<Args>(args)...);
|
return llvm::make_error<E>(std::forward<Args>(args)...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,19 +28,20 @@
|
||||||
|
|
||||||
namespace serene::errors {
|
namespace serene::errors {
|
||||||
|
|
||||||
|
// This class is used in the generated code
|
||||||
struct ErrorVariant {
|
struct ErrorVariant {
|
||||||
int id;
|
const int id;
|
||||||
const std::string title;
|
const std::string title;
|
||||||
const std::string desc;
|
const std::string desc;
|
||||||
const std::string help;
|
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) {
|
const char *h) {
|
||||||
return ErrorVariant(id, t, d, h);
|
return ErrorVariant(id, t, d, h);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
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){};
|
: id(id), title(t), desc(d), help(h){};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,3 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "serene/errors.h"
|
#include "serene/errors.h"
|
||||||
|
|
||||||
#define GET_ERRS_ARRAY
|
|
||||||
#include "serene/errors/errs.h.inc"
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef SERENE_TEST_CONTEXT_H
|
||||||
|
#define SERENE_TEST_CONTEXT_H
|
||||||
|
|
||||||
#include "serene/context.h"
|
#include "serene/context.h"
|
||||||
#include "serene/namespace.h"
|
#include "serene/namespace.h"
|
||||||
|
@ -162,3 +164,4 @@ TEST_CASE("context and jit", "[context]") {
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
#endif
|
||||||
|
|
|
@ -22,25 +22,37 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef SERENE_TEST_ERRORS_H
|
||||||
|
#define SERENE_TEST_ERRORS_H
|
||||||
|
|
||||||
#include "serene/errors.h"
|
#include "serene/errors.h"
|
||||||
#include "serene/exprs/symbol.h"
|
|
||||||
|
|
||||||
#include "../test_helpers.cpp.inc"
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/catch_all.hpp>
|
|
||||||
|
|
||||||
#include <llvm/Support/Casting.h>
|
#include <llvm/ADT/StringMap.h>
|
||||||
|
#include <llvm/Support/Error.h>
|
||||||
|
#include <llvm/Support/ErrorHandling.h>
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
namespace errors {
|
namespace errors {
|
||||||
|
|
||||||
TEST_CASE("Error Expression", "[expression]") {
|
TEST_CASE("Serene Error construction", "[errors]") {
|
||||||
std::unique_ptr<reader::LocationRange> range(dummyLocation());
|
{
|
||||||
auto err = exprs::makeAndCast<Error>(*range.get(), &DefExpectSymbol,
|
std::unique_ptr<reader::LocationRange> range(dummyLocation());
|
||||||
"Something Failed");
|
llvm::Error err = llvm::make_error<PassFailureError>(*range, "test error");
|
||||||
|
|
||||||
CHECK(err->getVariant()->id == E0001);
|
auto unhandled =
|
||||||
CHECK(err->toString() == "<Error E1: Something Failed>");
|
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 errors
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include "./context_tests.cpp.inc"
|
#include "./context_tests.cpp.inc"
|
||||||
#include "./environment_tests.cpp.inc"
|
#include "./environment_tests.cpp.inc"
|
||||||
|
#include "./errors/error_tests.cpp.inc"
|
||||||
#include "./setup.cpp.inc"
|
#include "./setup.cpp.inc"
|
||||||
// #include "./errors/error_tests.cpp.inc"
|
|
||||||
// #include "./exprs/expression_tests.cpp.inc"
|
// #include "./exprs/expression_tests.cpp.inc"
|
||||||
// #include "./exprs/list_tests.cpp.inc"
|
// #include "./exprs/list_tests.cpp.inc"
|
||||||
// #include "./exprs/number_tests.cpp.inc"
|
// #include "./exprs/number_tests.cpp.inc"
|
||||||
|
|
|
@ -16,6 +16,14 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
// The "serene/" part is due to a convention that we use in the project
|
||||||
#include "serene/errors-backend.h"
|
#include "serene/errors-backend.h"
|
||||||
|
|
||||||
|
@ -65,48 +73,7 @@ void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec,
|
||||||
<< "public:\n"
|
<< "public:\n"
|
||||||
<< " using llvm::ErrorInfo<" << recName << ", "
|
<< " using llvm::ErrorInfo<" << recName << ", "
|
||||||
<< "SereneError>::ErrorInfo;\n"
|
<< "SereneError>::ErrorInfo;\n"
|
||||||
<< " constexpr static const int ID = " << id << ";\n};\n\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<llvm::StringInit>(val.getValue());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ErrorsBackend::createNSBody(llvm::raw_ostream &os) {
|
void ErrorsBackend::createNSBody(llvm::raw_ostream &os) {
|
||||||
|
@ -135,41 +102,72 @@ void ErrorsBackend::createNSBody(llvm::raw_ostream &os) {
|
||||||
|
|
||||||
createErrorClass(i, *defRec, 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<int, ErrorVariant *> "
|
|
||||||
"variants{\n";
|
|
||||||
for (size_t i = 0; i < indexList->size(); i++) {
|
for (size_t i = 0; i < indexList->size(); i++) {
|
||||||
llvm::Record *defRec = indexList->getElementAsRecord(i);
|
llvm::Record *defRec = indexList->getElementAsRecord(i);
|
||||||
|
auto recName = defRec->getName();
|
||||||
|
|
||||||
if (!defRec->isSubClassOf("Error")) {
|
if (!defRec->isSubClassOf("Error")) {
|
||||||
continue;
|
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 ErrorsBackend::run(llvm::raw_ostream &os) {
|
||||||
(void)records;
|
(void)records;
|
||||||
llvm::emitSourceFileHeader("Serene's Errors collection", os);
|
llvm::emitSourceFileHeader("Serene's Errors collection", os);
|
||||||
|
|
||||||
|
// DO NOT GUARD THE HEADER WITH #ifndef ...
|
||||||
os << "#include \"serene/errors/base.h\"\n\n#include "
|
os << "#include \"serene/errors/base.h\"\n\n#include "
|
||||||
"<llvm/Support/Error.h>\n\n";
|
"<llvm/Support/Error.h>\n\n";
|
||||||
os << "#ifndef SERENE_ERRORS_ERRORS_H\n#define SERENE_ERRORS_ERRORS_H\n\n";
|
|
||||||
createNSBody(os);
|
createNSBody(os);
|
||||||
os << "#endif\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) {
|
void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) {
|
||||||
|
|
Loading…
Reference in New Issue