forked from M-Labs/nac3
core/irrt: add ErrorContext
ErrorContext allows IRRT to report a Python-like exception
This commit is contained in:
parent
80e56bc081
commit
9c3a10377f
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrt/int_defs.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file defines all ARTIQ-specific structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ARTIQ's `cslice` object
|
||||||
|
*
|
||||||
|
* See https://docs.rs/cslice/0.3.0/src/cslice/lib.rs.html#33-37
|
||||||
|
*/
|
||||||
|
template <typename SizeT>
|
||||||
|
struct CSlice {
|
||||||
|
const char *base;
|
||||||
|
SizeT len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Int type of ARTIQ's `Exception` IDs.
|
||||||
|
*/
|
||||||
|
typedef uint32_t ExceptionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ARTIQ's `Exception` object
|
||||||
|
*
|
||||||
|
* See https://github.com/m-labs/artiq/blob/b0d2705c385f64b6e6711c1726cd9178f40b598e/artiq/firmware/libeh/eh_artiq.rs#L1C1-L17C1
|
||||||
|
*/
|
||||||
|
template <typename SizeT>
|
||||||
|
struct Exception {
|
||||||
|
ExceptionId id;
|
||||||
|
CSlice<SizeT> file;
|
||||||
|
uint32_t line;
|
||||||
|
uint32_t column;
|
||||||
|
CSlice<SizeT> function;
|
||||||
|
CSlice<SizeT> message;
|
||||||
|
uint32_t param;
|
||||||
|
};
|
|
@ -0,0 +1,94 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrt/artiq_defs.hpp>
|
||||||
|
#include <irrt/int_defs.hpp>
|
||||||
|
#include <irrt/utils.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* @brief A (limited) set of known Error IDs
|
||||||
|
*/
|
||||||
|
struct ErrorIds {
|
||||||
|
ExceptionId index_error;
|
||||||
|
ExceptionId value_error;
|
||||||
|
ExceptionId assertion_error;
|
||||||
|
ExceptionId runtime_error;
|
||||||
|
ExceptionId type_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The IRRT error context object
|
||||||
|
*
|
||||||
|
* This object contains all the details needed to propagate Python-like Exceptions in
|
||||||
|
* IRRT - within IRRT itself or propagate out of extern calls from nac3core.
|
||||||
|
*/
|
||||||
|
struct ErrorContext {
|
||||||
|
/**
|
||||||
|
* @brief The set of all
|
||||||
|
*/
|
||||||
|
const ErrorIds *error_ids;
|
||||||
|
|
||||||
|
// Error thrown by IRRT
|
||||||
|
ExceptionId error_id;
|
||||||
|
const char *message_template;
|
||||||
|
uint64_t param1;
|
||||||
|
uint64_t param2;
|
||||||
|
uint64_t param3;
|
||||||
|
|
||||||
|
void initialize(const ErrorIds *error_ids) {
|
||||||
|
this->error_ids = error_ids;
|
||||||
|
clear_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_error() {
|
||||||
|
// Point the message_template to an empty str. Don't set it to nullptr
|
||||||
|
// as a sentinel
|
||||||
|
this->message_template = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_error(ExceptionId error_id, const char *message,
|
||||||
|
uint64_t param1 = 0, uint64_t param2 = 0,
|
||||||
|
uint64_t param3 = 0) {
|
||||||
|
this->error_id = error_id;
|
||||||
|
this->message_template = message;
|
||||||
|
this->param1 = param1;
|
||||||
|
this->param2 = param2;
|
||||||
|
this->param3 = param3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_error() { return !cstr_utils::is_empty(message_template); }
|
||||||
|
|
||||||
|
template <typename SizeT>
|
||||||
|
void get_error_str(CSlice<SizeT> *dst_str) {
|
||||||
|
dst_str->base = message_template;
|
||||||
|
dst_str->len = (SizeT)cstr_utils::length(message_template);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void __nac3_error_context_initialize(ErrorContext *errctx,
|
||||||
|
ErrorIds *error_ids) {
|
||||||
|
errctx->initialize(error_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __nac3_error_context_has_no_error(ErrorContext *errctx) {
|
||||||
|
return !errctx->has_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_error_context_get_error_str(ErrorContext *errctx,
|
||||||
|
CSlice<int32_t> *dst_str) {
|
||||||
|
errctx->get_error_str<int32_t>(dst_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_error_context_get_error_str64(ErrorContext *errctx,
|
||||||
|
CSlice<int64_t> *dst_str) {
|
||||||
|
errctx->get_error_str<int64_t>(dst_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for testing
|
||||||
|
void __nac3_error_dummy_raise(ErrorContext *errctx) {
|
||||||
|
errctx->set_error(errctx->error_ids->runtime_error,
|
||||||
|
"Error thrown from __nac3_error_dummy_raise");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrt/artiq_defs.hpp>
|
||||||
#include <irrt/core.hpp>
|
#include <irrt/core.hpp>
|
||||||
|
#include <irrt/error_context.hpp>
|
||||||
#include <irrt/int_defs.hpp>
|
#include <irrt/int_defs.hpp>
|
||||||
#include <irrt/utils.hpp>
|
#include <irrt/utils.hpp>
|
|
@ -113,4 +113,67 @@ void __assert_values_match(const char* file, int line, T expected, T got) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define assert_values_match(expected, got) \
|
#define assert_values_match(expected, got) \
|
||||||
__assert_values_match(__FILE__, __LINE__, expected, got)
|
__assert_values_match(__FILE__, __LINE__, expected, got)
|
||||||
|
|
||||||
|
// A fake set of ErrorIds for testing only
|
||||||
|
const ErrorIds TEST_ERROR_IDS = {
|
||||||
|
.index_error = 0,
|
||||||
|
.value_error = 1,
|
||||||
|
.assertion_error = 2,
|
||||||
|
.runtime_error = 3,
|
||||||
|
.type_error = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorContext create_testing_errctx() {
|
||||||
|
// Everything is global so it is fine to directly return a struct
|
||||||
|
// ErrorContext
|
||||||
|
ErrorContext errctx;
|
||||||
|
errctx.initialize(&TEST_ERROR_IDS);
|
||||||
|
return errctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_errctx_content(ErrorContext* errctx) {
|
||||||
|
if (errctx->has_error()) {
|
||||||
|
printf(
|
||||||
|
"(Error ID %d): %s ... where param1 = %ld, param2 = %ld, param3 = "
|
||||||
|
"%ld\n",
|
||||||
|
errctx->error_id, errctx->message_template, errctx->param1,
|
||||||
|
errctx->param2, errctx->param3);
|
||||||
|
} else {
|
||||||
|
printf("<no error>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __assert_errctx_no_error(const char* file, int line,
|
||||||
|
ErrorContext* errctx) {
|
||||||
|
if (errctx->has_error()) {
|
||||||
|
print_assertion_failed(file, line);
|
||||||
|
printf("Expecting no error but caught the following:\n\n");
|
||||||
|
print_errctx_content(errctx);
|
||||||
|
test_fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assert_errctx_no_error(errctx) \
|
||||||
|
__assert_errctx_no_error(__FILE__, __LINE__, errctx)
|
||||||
|
|
||||||
|
void __assert_errctx_has_error(const char* file, int line, ErrorContext* errctx,
|
||||||
|
ExceptionId expected_error_id) {
|
||||||
|
if (errctx->has_error()) {
|
||||||
|
if (errctx->error_id != expected_error_id) {
|
||||||
|
print_assertion_failed(file, line);
|
||||||
|
printf(
|
||||||
|
"Expecting error id %d but got error id %d. Error caught:\n\n",
|
||||||
|
expected_error_id, errctx->error_id);
|
||||||
|
print_errctx_content(errctx);
|
||||||
|
test_fail();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_assertion_failed(file, line);
|
||||||
|
printf("Expecting an error, but there is none.");
|
||||||
|
test_fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assert_errctx_has_error(errctx, expected_error_id) \
|
||||||
|
__assert_errctx_has_error(__FILE__, __LINE__, errctx, expected_error_id)
|
|
@ -577,17 +577,15 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_exn<G: CodeGenerator + ?Sized>(
|
pub fn raise_exn_impl<G: CodeGenerator + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
name: &str,
|
exn_id: NInt<'ctx, ExceptionId>,
|
||||||
msg: Struct<'ctx, CSlice<'ctx>>,
|
msg: Struct<'ctx, CSlice<'ctx>>,
|
||||||
params: [Option<NInt<'ctx, Int64>>; 3],
|
params: [Option<NInt<'ctx, Int64>>; 3],
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
// Define all used models
|
|
||||||
let sizet = generator.get_sizet(self.ctx);
|
let sizet = generator.get_sizet(self.ctx);
|
||||||
let exception_id_model = NIntModel(ExceptionId::default());
|
|
||||||
let exception_model = StructModel(Exception { sizet });
|
let exception_model = StructModel(Exception { sizet });
|
||||||
|
|
||||||
// Get `exn`
|
// Get `exn`
|
||||||
|
@ -596,17 +594,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
*self.exception_val.insert(exn)
|
*self.exception_val.insert(exn)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now load everything into `exn`
|
// Only have to store `exception_id`, `message`, and the parameters.
|
||||||
// Store `exception_id`
|
exn.gep(self, |f| f.exception_id).store(self, exn_id);
|
||||||
exn.gep(self, |f| f.exception_id).store(
|
|
||||||
self,
|
|
||||||
exception_id_model.constant(self.ctx, self.resolver.get_string_id(name) as u64),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Store `message`
|
|
||||||
exn.gep(self, |f| f.message).store(self, msg);
|
exn.gep(self, |f| f.message).store(self, msg);
|
||||||
|
|
||||||
// Store `params`
|
|
||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
if let Some(param) = param {
|
if let Some(param) = param {
|
||||||
exn.gep(self, |f| f.params[i]).store(self, *param);
|
exn.gep(self, |f| f.params[i]).store(self, *param);
|
||||||
|
@ -616,6 +606,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
gen_raise(generator, self, Some(exn), loc);
|
gen_raise(generator, self, Some(exn), loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raise_exn<G: CodeGenerator + ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
generator: &mut G,
|
||||||
|
name: &str,
|
||||||
|
msg: Struct<'ctx, CSlice<'ctx>>,
|
||||||
|
params: [Option<NInt<'ctx, Int64>>; 3],
|
||||||
|
loc: Location,
|
||||||
|
) {
|
||||||
|
let exn_id_model = NIntModel(ExceptionId::default());
|
||||||
|
|
||||||
|
let exn_id = self.resolver.get_string_id(name);
|
||||||
|
let exn_id = exn_id_model.constant(self.ctx, exn_id as u64);
|
||||||
|
|
||||||
|
self.raise_exn_impl(generator, exn_id, msg, params, loc)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn make_assert<G: CodeGenerator + ?Sized>(
|
pub fn make_assert<G: CodeGenerator + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
use crate::codegen::{model::*, structs::cslice::CSlice, CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
|
use super::util::get_sized_dependent_function_name;
|
||||||
|
|
||||||
|
/// The [`IntModel`] of nac3core's error ID.
|
||||||
|
///
|
||||||
|
/// It is always [`Int32`].
|
||||||
|
type ErrorId = Int32;
|
||||||
|
|
||||||
|
pub struct ErrorIdsFields {
|
||||||
|
pub index_error: Field<NIntModel<ErrorId>>,
|
||||||
|
pub value_error: Field<NIntModel<ErrorId>>,
|
||||||
|
pub assertion_error: Field<NIntModel<ErrorId>>,
|
||||||
|
pub runtime_error: Field<NIntModel<ErrorId>>,
|
||||||
|
pub type_error: Field<NIntModel<ErrorId>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to IRRT's `struct ErrorIds`
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
pub struct ErrorIds;
|
||||||
|
|
||||||
|
impl<'ctx> StructKind<'ctx> for ErrorIds {
|
||||||
|
type Fields = ErrorIdsFields;
|
||||||
|
|
||||||
|
fn struct_name(&self) -> &'static str {
|
||||||
|
"ErrorIds"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_fields(&self, builder: &mut FieldBuilder) -> Self::Fields {
|
||||||
|
Self::Fields {
|
||||||
|
index_error: builder.add_field_auto("index_error"),
|
||||||
|
value_error: builder.add_field_auto("value_error"),
|
||||||
|
assertion_error: builder.add_field_auto("assertion_error"),
|
||||||
|
runtime_error: builder.add_field_auto("runtime_error"),
|
||||||
|
type_error: builder.add_field_auto("type_error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ErrorContextFields {
|
||||||
|
pub error_ids: Field<PointerModel<StructModel<ErrorIds>>>,
|
||||||
|
pub error_id: Field<NIntModel<ErrorId>>,
|
||||||
|
pub message_template: Field<PointerModel<NIntModel<Byte>>>,
|
||||||
|
pub param1: Field<NIntModel<Int64>>,
|
||||||
|
pub param2: Field<NIntModel<Int64>>,
|
||||||
|
pub param3: Field<NIntModel<Int64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponds to IRRT's `struct ErrorContext`
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
pub struct ErrorContext;
|
||||||
|
|
||||||
|
impl<'ctx> StructKind<'ctx> for ErrorContext {
|
||||||
|
type Fields = ErrorContextFields;
|
||||||
|
|
||||||
|
fn struct_name(&self) -> &'static str {
|
||||||
|
"ErrorIds"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_fields(&self, builder: &mut FieldBuilder) -> Self::Fields {
|
||||||
|
Self::Fields {
|
||||||
|
error_ids: builder.add_field_auto("error_ids"),
|
||||||
|
error_id: builder.add_field_auto("error_id"),
|
||||||
|
message_template: builder.add_field_auto("message_template"),
|
||||||
|
param1: builder.add_field_auto("param1"),
|
||||||
|
param2: builder.add_field_auto("param2"),
|
||||||
|
param3: builder.add_field_auto("param3"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare ErrorIds
|
||||||
|
fn build_error_ids<'ctx>(ctx: &CodeGenContext<'ctx, '_>) -> Pointer<'ctx, StructModel<ErrorIds>> {
|
||||||
|
// ErrorIdsLens.get_fields(ctx.ctx).assertion_error.
|
||||||
|
let error_ids = StructModel(ErrorIds).alloca(ctx, "error_ids");
|
||||||
|
let i32_model = NIntModel(Int32);
|
||||||
|
// i32_model.make_constant()
|
||||||
|
|
||||||
|
let get_string_id =
|
||||||
|
|string_id| i32_model.constant(ctx.ctx, ctx.resolver.get_string_id(string_id) as u64);
|
||||||
|
|
||||||
|
error_ids.gep(ctx, |f| f.index_error).store(ctx, get_string_id("0:IndexError"));
|
||||||
|
error_ids.gep(ctx, |f| f.value_error).store(ctx, get_string_id("0:ValueError"));
|
||||||
|
error_ids.gep(ctx, |f| f.assertion_error).store(ctx, get_string_id("0:AssertionError"));
|
||||||
|
error_ids.gep(ctx, |f| f.runtime_error).store(ctx, get_string_id("0:RuntimeError"));
|
||||||
|
error_ids.gep(ctx, |f| f.type_error).store(ctx, get_string_id("0:TypeError"));
|
||||||
|
|
||||||
|
error_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_initialize<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
perrctx: Pointer<'ctx, StructModel<ErrorContext>>,
|
||||||
|
perror_ids: Pointer<'ctx, StructModel<ErrorIds>>,
|
||||||
|
) {
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_context_initialize")
|
||||||
|
.arg("errctx", perrctx)
|
||||||
|
.arg("error_ids", perror_ids)
|
||||||
|
.returning_void();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_has_no_error<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: Pointer<'ctx, StructModel<ErrorContext>>,
|
||||||
|
) -> NInt<'ctx, Bool> {
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_context_has_no_error")
|
||||||
|
.arg("errctx", errctx)
|
||||||
|
.returning("has_error", NIntModel(Bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_error_context_get_error_str<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
errctx: Pointer<'ctx, StructModel<ErrorContext>>,
|
||||||
|
dst_str: Pointer<'ctx, StructModel<CSlice<'ctx>>>,
|
||||||
|
) {
|
||||||
|
let sizet = generator.get_sizet(ctx.ctx);
|
||||||
|
|
||||||
|
FunctionBuilder::begin(
|
||||||
|
ctx,
|
||||||
|
&get_sized_dependent_function_name(sizet, "__nac3_error_context_get_error_str"),
|
||||||
|
)
|
||||||
|
.arg("errctx", errctx)
|
||||||
|
.arg("dst_str", dst_str)
|
||||||
|
.returning_void();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup a [`ErrorContext`] that could
|
||||||
|
/// be passed to IRRT functions taking in a `ErrorContext* errctx`
|
||||||
|
/// for error reporting purposes.
|
||||||
|
///
|
||||||
|
/// Also see: [`check_error_context`]
|
||||||
|
pub fn setup_error_context<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
) -> Pointer<'ctx, StructModel<ErrorContext>> {
|
||||||
|
let error_ids = build_error_ids(ctx);
|
||||||
|
let errctx_ptr = StructModel(ErrorContext).alloca(ctx, "errctx");
|
||||||
|
call_nac3_error_context_initialize(ctx, errctx_ptr, error_ids);
|
||||||
|
errctx_ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check a [`ErrorContext`] to see
|
||||||
|
/// if it contains error.
|
||||||
|
///
|
||||||
|
/// If there is an error, an LLVM exception will be raised at runtime.
|
||||||
|
pub fn check_error_context<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
errctx_ptr: Pointer<'ctx, StructModel<ErrorContext>>,
|
||||||
|
) {
|
||||||
|
let sizet = generator.get_sizet(ctx.ctx);
|
||||||
|
let cslice_model = StructModel(CSlice { sizet });
|
||||||
|
|
||||||
|
let current_bb = ctx.builder.get_insert_block().unwrap();
|
||||||
|
let irrt_has_error_bb = ctx.ctx.insert_basic_block_after(current_bb, "irrt_has_error");
|
||||||
|
let end_bb = ctx.ctx.insert_basic_block_after(irrt_has_error_bb, "end");
|
||||||
|
|
||||||
|
// Inserting into `current_bb`
|
||||||
|
let has_error = call_nac3_error_context_has_no_error(ctx, errctx_ptr);
|
||||||
|
ctx.builder.build_conditional_branch(has_error.value, irrt_has_error_bb, end_bb).unwrap();
|
||||||
|
|
||||||
|
// Inserting into `irrt_has_error_bb`
|
||||||
|
ctx.builder.position_at_end(irrt_has_error_bb);
|
||||||
|
|
||||||
|
// Load all the values for `ctx.make_assert_impl_by_id`
|
||||||
|
let pstr = cslice_model.alloca(ctx, "error_str");
|
||||||
|
call_nac3_error_context_get_error_str(generator, ctx, errctx_ptr, pstr);
|
||||||
|
|
||||||
|
let error_id = errctx_ptr.gep(ctx, |f| f.error_id).load(ctx, "error_id");
|
||||||
|
let msg = pstr.load(ctx, "msg");
|
||||||
|
let param1 = errctx_ptr.gep(ctx, |f| f.param1).load(ctx, "param1");
|
||||||
|
let param2 = errctx_ptr.gep(ctx, |f| f.param2).load(ctx, "param2");
|
||||||
|
let param3 = errctx_ptr.gep(ctx, |f| f.param3).load(ctx, "param3");
|
||||||
|
|
||||||
|
ctx.raise_exn_impl(
|
||||||
|
generator,
|
||||||
|
error_id,
|
||||||
|
msg,
|
||||||
|
[Some(param1), Some(param2), Some(param3)],
|
||||||
|
ctx.current_loc,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Position to `end_bb` for continuation
|
||||||
|
ctx.builder.position_at_end(end_bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_dummy_raise<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext,
|
||||||
|
) {
|
||||||
|
let errctx = setup_error_context(ctx);
|
||||||
|
FunctionBuilder::begin(ctx, "__nac3_error_dummy_raise").arg("errctx", errctx).returning_void();
|
||||||
|
check_error_context(generator, ctx, errctx);
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::Type;
|
||||||
|
|
||||||
|
mod error_context;
|
||||||
mod test;
|
mod test;
|
||||||
|
mod util;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
classes::{
|
classes::{
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
use crate::codegen::model::*;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_sized_dependent_function_name(sizet: SizeTModel<'_>, fn_name: &str) -> String {
|
||||||
|
// When its 32-bits, the function name is "{fn_name}"
|
||||||
|
// When its 64-bits, the function name is "{fn_name}64"
|
||||||
|
let mut fn_name = fn_name.to_owned();
|
||||||
|
match sizet.0.get_bit_width() {
|
||||||
|
32 => {}
|
||||||
|
64 => fn_name.push_str("64"),
|
||||||
|
bit_width => {
|
||||||
|
panic!("Unsupported int type bit width {bit_width}, must be either 32-bits or 64-bits")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn_name
|
||||||
|
}
|
Loading…
Reference in New Issue