diff --git a/nac3core/irrt/irrt/error_context.hpp b/nac3core/irrt/irrt/error_context.hpp index c1dfa6ec..824f6eb7 100644 --- a/nac3core/irrt/irrt/error_context.hpp +++ b/nac3core/irrt/irrt/error_context.hpp @@ -11,22 +11,38 @@ struct Str { SizeT length; }; +// A limited set of errors IRRT could use. +typedef uint32_t ErrorId; +struct ErrorIds { + ErrorId index_error; + ErrorId value_error; + ErrorId assertion_error; + ErrorId runtime_error; +}; + struct ErrorContext { + // Context + ErrorIds* error_ids; + + // Error thrown by IRRT + ErrorId error_id; const char* message_template; // MUST BE `&'static` uint64_t param1; uint64_t param2; uint64_t param3; - void initialize() { + void initialize(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 - set_error(""); + this->message_template = ""; } - void set_error(const char* message, uint64_t param1 = 0, uint64_t param2 = 0, uint64_t param3 = 0) { + void set_error(ErrorId 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; @@ -47,8 +63,8 @@ struct ErrorContext { extern "C" { -void __nac3_error_context_initialize(ErrorContext* errctx) { - errctx->initialize(); +void __nac3_error_context_initialize(ErrorContext* errctx, ErrorIds* error_ids) { + errctx->initialize(error_ids); } uint8_t __nac3_error_context_has_no_error(ErrorContext* errctx) { @@ -64,6 +80,6 @@ void __nac3_error_context_get_error_str64(ErrorContext* errctx, Str *ds } void __nac3_error_dummy_raise(ErrorContext* errctx) { - errctx->set_error("THROWN FROM __nac3_error_dummy_raise!!!!!!"); + errctx->set_error(errctx->error_ids->runtime_error, "THROWN FROM __nac3_error_dummy_raise!!!!!!"); } } \ No newline at end of file diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index c42c8444..c9f96385 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -576,6 +576,21 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { params: [Option>; 3], loc: Location, ) { + let error_id = self.resolver.get_string_id(name); + let error_id = self.ctx.i32_type().const_int(error_id as u64, false); + self.raise_exn_impl(generator, error_id, msg, params, loc); + } + + pub fn raise_exn_impl( + &mut self, + generator: &mut G, + error_id: IntValue<'ctx>, + msg: BasicValueEnum<'ctx>, + params: [Option>; 3], + loc: Location, + ) { + assert_eq!(error_id.get_type().get_bit_width(), 32); + let zelf = if let Some(exception_val) = self.exception_val { exception_val } else { @@ -588,8 +603,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { let zero = int32.const_zero(); unsafe { let id_ptr = self.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id").unwrap(); - let id = self.resolver.get_string_id(name); - self.builder.build_store(id_ptr, int32.const_int(id as u64, false)).unwrap(); + self.builder.build_store(id_ptr, error_id).unwrap(); let ptr = self .builder .build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg") diff --git a/nac3core/src/codegen/irrt/classes.rs b/nac3core/src/codegen/irrt/classes.rs index dfa8c5d2..c1b12c6e 100644 --- a/nac3core/src/codegen/irrt/classes.rs +++ b/nac3core/src/codegen/irrt/classes.rs @@ -93,7 +93,36 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens { } } +pub struct ErrorIdsFields<'ctx> { + pub index_error: GepGetter>, + pub value_error: GepGetter>, + pub assertion_error: GepGetter>, + pub runtime_error: GepGetter>, +} + +#[derive(Debug, Clone)] +pub struct ErrorIdsLens; + +impl<'ctx> StructureOptic<'ctx> for ErrorIdsLens { + type Fields = ErrorIdsFields<'ctx>; + + fn struct_name(&self) -> &'static str { + "ErrorIds" + } + + fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields { + let i32_lens = IntLens(builder.ctx.i32_type()); + ErrorIdsFields { + index_error: builder.add_field("index_error", i32_lens), + value_error: builder.add_field("value_error", i32_lens), + assertion_error: builder.add_field("assertion_error", i32_lens), + runtime_error: builder.add_field("runtime_error", i32_lens), + } + } +} + pub struct ErrorContextFields<'ctx> { + pub error_ids: GepGetter>, pub message_template: GepGetter>>, pub param1: GepGetter>, pub param2: GepGetter>, @@ -115,6 +144,7 @@ impl<'ctx> StructureOptic<'ctx> for ErrorContextLens { builder: &mut crate::codegen::optics::FieldBuilder<'ctx>, ) -> Self::Fields { ErrorContextFields { + error_ids: builder.add_field("error_ids", AddressLens(ErrorIdsLens)), message_template: builder .add_field("message_template", AddressLens(IntLens(builder.ctx.i8_type()))), param1: builder.add_field("param1", IntLens(builder.ctx.i64_type())), diff --git a/nac3core/src/codegen/irrt/new.rs b/nac3core/src/codegen/irrt/new.rs index 5c992d4b..0dc78c62 100644 --- a/nac3core/src/codegen/irrt/new.rs +++ b/nac3core/src/codegen/irrt/new.rs @@ -3,15 +3,13 @@ use inkwell::{ values::{AnyValue, BasicMetadataValueEnum, IntValue}, }; -use crate::{ - codegen::{ - optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism}, - CodeGenContext, CodeGenerator, - }, - util::SizeVariant, +use crate::codegen::{ + optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism}, + CodeGenContext, CodeGenerator, }; +use crate::util::SizeVariant; -use super::classes::{ErrorContextLens, StrLens}; +use super::classes::{ErrorContextLens, ErrorIdsLens, StrLens}; fn get_size_variant(ty: IntType) -> SizeVariant { match ty.get_bit_width() { @@ -82,12 +80,34 @@ impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> { } } +fn build_error_ids<'ctx>(ctx: &CodeGenContext<'ctx, '_>) -> Address<'ctx, ErrorIdsLens> { + // ErrorIdsLens.get_fields(ctx.ctx).assertion_error. + let error_ids = ErrorIdsLens.alloca(ctx, "error_ids"); + let llvm_i32 = ctx.ctx.i32_type(); + + let get_string_id = + |string_id| llvm_i32.const_int(ctx.resolver.get_string_id(string_id) as u64, false); + + error_ids.view(ctx, |fields| &fields.index_error).store(ctx, &get_string_id("0:IndexError")); + error_ids.view(ctx, |fields| &fields.value_error).store(ctx, &get_string_id("0:ValueError")); + error_ids + .view(ctx, |fields| &fields.assertion_error) + .store(ctx, &get_string_id("0:AssertionError")); + error_ids + .view(ctx, |fields| &fields.runtime_error) + .store(ctx, &get_string_id("0:RuntimeError")); + + error_ids +} + pub fn call_nac3_error_context_initialize<'ctx>( ctx: &CodeGenContext<'ctx, '_>, errctx: &Address<'ctx, ErrorContextLens>, + error_ids: &Address<'ctx, ErrorIdsLens>, ) { FunctionBuilder::begin(ctx, "__nac3_error_context_initialize") .arg("errctx", &AddressLens(ErrorContextLens), errctx) + .arg("error_ids", &AddressLens(ErrorIdsLens), error_ids) .returning_void(); } @@ -130,9 +150,10 @@ pub fn test_dummy_raise( ) { let size_type = generator.get_size_type(ctx.ctx); + let error_ids = build_error_ids(ctx); let errctx_ptr = ErrorContextLens.alloca(ctx, "errctx"); - call_nac3_error_context_initialize(ctx, &errctx_ptr); + call_nac3_error_context_initialize(ctx, &errctx_ptr, &error_ids); call_nac3_dummy_raise(ctx, &errctx_ptr); let has_error = call_nac3_error_context_has_no_error(ctx, &errctx_ptr); diff --git a/nac3core/src/codegen/optics.rs b/nac3core/src/codegen/optics.rs index 8a7b0439..e38d30aa 100644 --- a/nac3core/src/codegen/optics.rs +++ b/nac3core/src/codegen/optics.rs @@ -172,7 +172,7 @@ impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> { // To make [`Address`] convenient to use impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> { - pub fn set(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) { + pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) { self.addressee_optic.set(ctx, self.address, value); } }