forked from M-Labs/nac3
123 lines
3.5 KiB
C++
123 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <irrt/cslice.hpp>
|
|
#include <irrt/int_defs.hpp>
|
|
#include <irrt/util.hpp>
|
|
|
|
/**
|
|
* @brief The int type of ARTIQ exception IDs.
|
|
*
|
|
* It is always `int32_t`
|
|
*/
|
|
typedef int32_t ExceptionId;
|
|
|
|
/*
|
|
* A set of exceptions IRRT can use.
|
|
* Must be synchronized with `setup_irrt_exceptions` in `nac3core/src/codegen/irrt/mod.rs`.
|
|
* All exception IDs are initialized by `setup_irrt_exceptions`.
|
|
*/
|
|
#ifdef IRRT_TESTING
|
|
// If we are doing IRRT tests (i.e., running `cargo test -F test`), define them with a fake set of IDs.
|
|
ExceptionId EXN_INDEX_ERROR = 0;
|
|
ExceptionId EXN_VALUE_ERROR = 1;
|
|
ExceptionId EXN_ASSERTION_ERROR = 2;
|
|
ExceptionId EXN_RUNTIME_ERROR = 3;
|
|
ExceptionId EXN_TYPE_ERROR = 4;
|
|
#else
|
|
extern "C" {
|
|
ExceptionId EXN_INDEX_ERROR;
|
|
ExceptionId EXN_VALUE_ERROR;
|
|
ExceptionId EXN_ASSERTION_ERROR;
|
|
ExceptionId EXN_RUNTIME_ERROR;
|
|
ExceptionId EXN_TYPE_ERROR;
|
|
}
|
|
#endif
|
|
|
|
namespace {
|
|
/**
|
|
* @brief NAC3's Exception struct
|
|
*/
|
|
template <typename SizeT>
|
|
struct Exception {
|
|
ExceptionId id;
|
|
CSlice<SizeT> filename;
|
|
int32_t line;
|
|
int32_t column;
|
|
CSlice<SizeT> function;
|
|
CSlice<SizeT> msg;
|
|
int64_t params[3];
|
|
};
|
|
} // namespace
|
|
|
|
// Declare/Define `__nac3_raise`
|
|
#ifdef IRRT_TESTING
|
|
#include <cstdio>
|
|
void __nac3_raise(void* err) {
|
|
// TODO: Print the error content?
|
|
printf("__nac3_raise called. Exiting...\n");
|
|
exit(1);
|
|
}
|
|
#else
|
|
/**
|
|
* @brief Extern function to `__nac3_raise`
|
|
*
|
|
* The parameter `err` could be `Exception<int32_t>` or `Exception<int64_t>`. The caller
|
|
* must make sure to pass `Exception`s with the correct `SizeT` depending on the `size_t` of the runtime.
|
|
*/
|
|
extern "C" void __nac3_raise(void* err);
|
|
#endif
|
|
|
|
namespace {
|
|
const int64_t NO_PARAM = 0;
|
|
|
|
// Helper function to raise an exception with `__nac3_raise`
|
|
// Do not use this function directly. See `raise_exception`.
|
|
template <typename SizeT>
|
|
void _raise_exception_helper(ExceptionId id, const char* filename, int32_t line,
|
|
const char* function, const char* msg,
|
|
int64_t param0, int64_t param1, int64_t param2) {
|
|
Exception<SizeT> e = {
|
|
.id = id,
|
|
.filename = {.base = (uint8_t*)filename,
|
|
.len = (int32_t)cstr_utils::length(filename)},
|
|
.line = line,
|
|
.column = 0,
|
|
.function = {.base = (uint8_t*)function,
|
|
.len = (int32_t)cstr_utils::length(function)},
|
|
.msg = {.base = (uint8_t*)msg, .len = (int32_t)cstr_utils::length(msg)},
|
|
};
|
|
e.params[0] = param0;
|
|
e.params[1] = param1;
|
|
e.params[2] = param2;
|
|
__nac3_raise((void*)&e);
|
|
__builtin_unreachable();
|
|
}
|
|
|
|
/**
|
|
* @brief Raise an exception with location details (location in the IRRT source files).
|
|
* @param SizeT The runtime `size_t` type.
|
|
* @param id The ID of the exception to raise.
|
|
* @param msg A global constant C-string of the error message.
|
|
*
|
|
* `param0` and `param2` are optional format arguments of `msg`. They should be set to
|
|
* `NO_PARAM` to indicate they are unused.
|
|
*/
|
|
#define raise_exception(SizeT, id, msg, param0, param1, param2) \
|
|
_raise_exception_helper<SizeT>(id, __FILE__, __LINE__, __FUNCTION__, msg, \
|
|
param0, param1, param2)
|
|
|
|
/**
|
|
* @brief Throw a dummy error for testing.
|
|
*/
|
|
template <typename SizeT>
|
|
void throw_dummy_error() {
|
|
raise_exception(SizeT, EXN_RUNTIME_ERROR, "dummy error", NO_PARAM, NO_PARAM,
|
|
NO_PARAM);
|
|
}
|
|
} // namespace
|
|
|
|
extern "C" {
|
|
void __nac3_throw_dummy_error() { throw_dummy_error<int32_t>(); }
|
|
|
|
void __nac3_throw_dummy_error64() { throw_dummy_error<int64_t>(); }
|
|
} |