forked from M-Labs/nac3
[core] codegen: Add Exception{Type,Value}
This commit is contained in:
parent
57552fb2f6
commit
064aa0411f
@ -32,7 +32,9 @@ use super::{
|
|||||||
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
|
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
|
||||||
gen_var,
|
gen_var,
|
||||||
},
|
},
|
||||||
types::{ndarray::NDArrayType, ListType, OptionType, RangeType, StringType, TupleType},
|
types::{
|
||||||
|
ndarray::NDArrayType, ExceptionType, ListType, OptionType, RangeType, StringType, TupleType,
|
||||||
|
},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
||||||
@ -576,42 +578,35 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
|||||||
params: [Option<IntValue<'ctx>>; 3],
|
params: [Option<IntValue<'ctx>>; 3],
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
|
let llvm_i32 = self.ctx.i32_type();
|
||||||
|
let llvm_i64 = self.ctx.i64_type();
|
||||||
|
let llvm_exn = ExceptionType::get_instance(generator, self);
|
||||||
|
|
||||||
let zelf = if let Some(exception_val) = self.exception_val {
|
let zelf = if let Some(exception_val) = self.exception_val {
|
||||||
exception_val
|
llvm_exn.map_pointer_value(exception_val, Some("exn"))
|
||||||
} else {
|
} else {
|
||||||
let ty = self.get_llvm_type(generator, self.primitives.exception).into_pointer_type();
|
let zelf = llvm_exn.alloca_var(generator, self, Some("exn"));
|
||||||
let zelf_ty: BasicTypeEnum = ty.get_element_type().into_struct_type().into();
|
self.exception_val = Some(zelf.as_abi_value(self));
|
||||||
let zelf = generator.gen_var_alloc(self, zelf_ty, Some("exn")).unwrap();
|
zelf
|
||||||
*self.exception_val.insert(zelf)
|
|
||||||
};
|
};
|
||||||
let int32 = self.ctx.i32_type();
|
|
||||||
let zero = int32.const_zero();
|
let id = self.resolver.get_string_id(name);
|
||||||
unsafe {
|
zelf.store_name(self, llvm_i32.const_int(id as u64, false));
|
||||||
let id_ptr = self.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id").unwrap();
|
zelf.store_message(self, msg.into_struct_value());
|
||||||
let id = self.resolver.get_string_id(name);
|
zelf.store_params(
|
||||||
self.builder.build_store(id_ptr, int32.const_int(id as u64, false)).unwrap();
|
self,
|
||||||
let ptr = self
|
params
|
||||||
.builder
|
.iter()
|
||||||
.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg")
|
.map(|p| {
|
||||||
.unwrap();
|
p.map_or(llvm_i64.const_zero(), |v| {
|
||||||
self.builder.build_store(ptr, msg).unwrap();
|
self.builder.build_int_s_extend(v, self.ctx.i64_type(), "sext").unwrap()
|
||||||
let i64_zero = self.ctx.i64_type().const_zero();
|
})
|
||||||
for (i, attr_ind) in [6, 7, 8].iter().enumerate() {
|
})
|
||||||
let ptr = self
|
.collect_array()
|
||||||
.builder
|
.as_ref()
|
||||||
.build_in_bounds_gep(
|
.unwrap(),
|
||||||
zelf,
|
);
|
||||||
&[zero, int32.const_int(*attr_ind, false)],
|
gen_raise(generator, self, Some(&zelf), loc);
|
||||||
"exn.param",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let val = params[i].map_or(i64_zero, |v| {
|
|
||||||
self.builder.build_int_s_extend(v, self.ctx.i64_type(), "sext").unwrap()
|
|
||||||
});
|
|
||||||
self.builder.build_store(ptr, val).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gen_raise(generator, self, Some(&zelf.into()), loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_assert<G: CodeGenerator + ?Sized>(
|
pub fn make_assert<G: CodeGenerator + ?Sized>(
|
||||||
|
@ -17,10 +17,10 @@ use super::{
|
|||||||
gen_in_range_check,
|
gen_in_range_check,
|
||||||
irrt::{handle_slice_indices, list_slice_assignment},
|
irrt::{handle_slice_indices, list_slice_assignment},
|
||||||
macros::codegen_unreachable,
|
macros::codegen_unreachable,
|
||||||
types::{ndarray::NDArrayType, RangeType},
|
types::{ndarray::NDArrayType, ExceptionType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{RustNDIndex, ScalarOrNDArray},
|
ndarray::{RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue,
|
ArrayLikeIndexer, ArraySliceValue, ExceptionValue, ListValue, ProxyValue,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -1337,43 +1337,19 @@ pub fn exn_constructor<'ctx>(
|
|||||||
pub fn gen_raise<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn gen_raise<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
exception: Option<&BasicValueEnum<'ctx>>,
|
exception: Option<&ExceptionValue<'ctx>>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
if let Some(exception) = exception {
|
if let Some(exception) = exception {
|
||||||
unsafe {
|
exception.store_location(generator, ctx, loc);
|
||||||
let int32 = ctx.ctx.i32_type();
|
|
||||||
let zero = int32.const_zero();
|
|
||||||
let exception = exception.into_pointer_value();
|
|
||||||
let file_ptr = ctx
|
|
||||||
.builder
|
|
||||||
.build_in_bounds_gep(exception, &[zero, int32.const_int(1, false)], "file_ptr")
|
|
||||||
.unwrap();
|
|
||||||
let filename = ctx.gen_string(generator, loc.file.0);
|
|
||||||
ctx.builder.build_store(file_ptr, filename).unwrap();
|
|
||||||
let row_ptr = ctx
|
|
||||||
.builder
|
|
||||||
.build_in_bounds_gep(exception, &[zero, int32.const_int(2, false)], "row_ptr")
|
|
||||||
.unwrap();
|
|
||||||
ctx.builder.build_store(row_ptr, int32.const_int(loc.row as u64, false)).unwrap();
|
|
||||||
let col_ptr = ctx
|
|
||||||
.builder
|
|
||||||
.build_in_bounds_gep(exception, &[zero, int32.const_int(3, false)], "col_ptr")
|
|
||||||
.unwrap();
|
|
||||||
ctx.builder.build_store(col_ptr, int32.const_int(loc.column as u64, false)).unwrap();
|
|
||||||
|
|
||||||
let current_fun = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current_fun = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
|
||||||
let fun_name = ctx.gen_string(generator, current_fun.get_name().to_str().unwrap());
|
let fun_name = ctx.gen_string(generator, current_fun.get_name().to_str().unwrap());
|
||||||
let name_ptr = ctx
|
exception.store_func(ctx, fun_name);
|
||||||
.builder
|
|
||||||
.build_in_bounds_gep(exception, &[zero, int32.const_int(4, false)], "name_ptr")
|
|
||||||
.unwrap();
|
|
||||||
ctx.builder.build_store(name_ptr, fun_name).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let raise = get_builtins(generator, ctx, "__nac3_raise");
|
let raise = get_builtins(generator, ctx, "__nac3_raise");
|
||||||
let exception = *exception;
|
let exception = *exception;
|
||||||
ctx.build_call_or_invoke(raise, &[exception], "raise");
|
ctx.build_call_or_invoke(raise, &[exception.as_abi_value(ctx).into()], "raise");
|
||||||
} else {
|
} else {
|
||||||
let resume = get_builtins(generator, ctx, "__nac3_resume");
|
let resume = get_builtins(generator, ctx, "__nac3_resume");
|
||||||
ctx.build_call_or_invoke(resume, &[], "resume");
|
ctx.build_call_or_invoke(resume, &[], "resume");
|
||||||
@ -1860,6 +1836,8 @@ pub fn gen_stmt<G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
let exc = ExceptionType::get_instance(generator, ctx)
|
||||||
|
.map_pointer_value(exc.into_pointer_value(), None);
|
||||||
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
||||||
} else {
|
} else {
|
||||||
gen_raise(generator, ctx, None, stmt.location);
|
gen_raise(generator, ctx, None, stmt.location);
|
||||||
|
257
nac3core/src/codegen/types/exception.rs
Normal file
257
nac3core/src/codegen/types/exception.rs
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
use inkwell::{
|
||||||
|
context::{AsContextRef, Context},
|
||||||
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
|
values::{IntValue, PointerValue, StructValue},
|
||||||
|
AddressSpace,
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use nac3core_derive::StructFields;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
structure::{check_struct_type_matches_fields, StructField, StructFields, StructProxyType},
|
||||||
|
ProxyType,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
codegen::{values::ExceptionValue, CodeGenContext, CodeGenerator},
|
||||||
|
typecheck::typedef::{Type, TypeEnum},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Proxy type for an `Exception` in LLVM.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub struct ExceptionType<'ctx> {
|
||||||
|
ty: PointerType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, StructFields)]
|
||||||
|
pub struct ExceptionStructFields<'ctx> {
|
||||||
|
/// The ID of the exception name.
|
||||||
|
#[value_type(i32_type())]
|
||||||
|
pub name: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
|
||||||
|
/// The file where the exception originated from.
|
||||||
|
#[value_type(get_struct_type("str").unwrap())]
|
||||||
|
pub file: StructField<'ctx, StructValue<'ctx>>,
|
||||||
|
|
||||||
|
/// The line number where the exception originated from.
|
||||||
|
#[value_type(i32_type())]
|
||||||
|
pub line: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
|
||||||
|
/// The column number where the exception originated from.
|
||||||
|
#[value_type(i32_type())]
|
||||||
|
pub col: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
|
||||||
|
/// The function name where the exception originated from.
|
||||||
|
#[value_type(get_struct_type("str").unwrap())]
|
||||||
|
pub func: StructField<'ctx, StructValue<'ctx>>,
|
||||||
|
|
||||||
|
/// The exception message.
|
||||||
|
#[value_type(get_struct_type("str").unwrap())]
|
||||||
|
pub message: StructField<'ctx, StructValue<'ctx>>,
|
||||||
|
|
||||||
|
#[value_type(i64_type())]
|
||||||
|
pub param0: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
|
||||||
|
#[value_type(i64_type())]
|
||||||
|
pub param1: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
|
||||||
|
#[value_type(i64_type())]
|
||||||
|
pub param2: StructField<'ctx, IntValue<'ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ExceptionType<'ctx> {
|
||||||
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
|
#[must_use]
|
||||||
|
fn fields(
|
||||||
|
ctx: impl AsContextRef<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> ExceptionStructFields<'ctx> {
|
||||||
|
ExceptionStructFields::new(ctx, llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an LLVM type corresponding to the expected structure of an `Exception`.
|
||||||
|
#[must_use]
|
||||||
|
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
|
assert!(ctx.get_struct_type("str").is_some());
|
||||||
|
|
||||||
|
let field_tys =
|
||||||
|
Self::fields(ctx, llvm_usize).into_iter().map(|field| field.1).collect_vec();
|
||||||
|
|
||||||
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
let llvm_str = Self::llvm_type(ctx, llvm_usize);
|
||||||
|
|
||||||
|
Self { ty: llvm_str, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ExceptionType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ExceptionType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`ExceptionType`] from a [unifier type][Type].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_unifier_type(ctx: &mut CodeGenContext<'ctx, '_>, ty: Type) -> Self {
|
||||||
|
// Check unifier type
|
||||||
|
assert!(
|
||||||
|
matches!(&*ctx.unifier.get_ty_immutable(ty), TypeEnum::TObj { obj_id, .. } if *obj_id == ctx.primitives.exception.obj_id(&ctx.unifier).unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`ExceptionType`] from a [`StructType`] representing an `Exception`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`ExceptionType`] from a [`PointerType`] representing an `Exception`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an instance of [`ExceptionType`] by obtaining the LLVM representation of the builtin
|
||||||
|
/// `Exception` type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_instance<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_pointer_type(
|
||||||
|
ctx.get_llvm_type(generator, ctx.primitives.exception).into_pointer_type(),
|
||||||
|
ctx.get_size_type(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates an instance of [`ExceptionValue`] as if by calling `alloca` on the base type.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca(
|
||||||
|
&self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
|
self.raw_alloca(ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates an instance of [`ExceptionValue`] as if by calling `alloca` on the base type.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca_var`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca_var<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
|
self.raw_alloca_var(generator, ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`ExceptionValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`ExceptionValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ProxyType<'ctx> for ExceptionType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
|
type Base = PointerType<'ctx>;
|
||||||
|
type Value = ExceptionValue<'ctx>;
|
||||||
|
|
||||||
|
fn is_representable(
|
||||||
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
|
let ctx = ty.get_context();
|
||||||
|
|
||||||
|
let llvm_ty = ty.get_element_type();
|
||||||
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
|
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(Self::fields(ctx, llvm_usize), llvm_ty, "exception", &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_base_type(&self) -> Self::Base {
|
||||||
|
self.ty
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for ExceptionType<'ctx> {
|
||||||
|
type StructFields = ExceptionStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.ty.get_context(), self.llvm_usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<ExceptionType<'ctx>> for PointerType<'ctx> {
|
||||||
|
fn from(value: ExceptionType<'ctx>) -> Self {
|
||||||
|
value.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
@ -25,12 +25,14 @@ use super::{
|
|||||||
values::{ArraySliceValue, ProxyValue},
|
values::{ArraySliceValue, ProxyValue},
|
||||||
{CodeGenContext, CodeGenerator},
|
{CodeGenContext, CodeGenerator},
|
||||||
};
|
};
|
||||||
|
pub use exception::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use option::*;
|
pub use option::*;
|
||||||
pub use range::*;
|
pub use range::*;
|
||||||
pub use string::*;
|
pub use string::*;
|
||||||
pub use tuple::*;
|
pub use tuple::*;
|
||||||
|
|
||||||
|
mod exception;
|
||||||
mod list;
|
mod list;
|
||||||
pub mod ndarray;
|
pub mod ndarray;
|
||||||
mod option;
|
mod option;
|
||||||
|
188
nac3core/src/codegen/values/exception.rs
Normal file
188
nac3core/src/codegen/values/exception.rs
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
use inkwell::{
|
||||||
|
types::IntType,
|
||||||
|
values::{IntValue, PointerValue, StructValue},
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use nac3parser::ast::Location;
|
||||||
|
|
||||||
|
use super::{structure::StructProxyValue, ProxyValue, StringValue};
|
||||||
|
use crate::codegen::{
|
||||||
|
types::{
|
||||||
|
structure::{StructField, StructProxyType},
|
||||||
|
ExceptionType,
|
||||||
|
},
|
||||||
|
CodeGenContext, CodeGenerator,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Proxy type for accessing an `Exception` value in LLVM.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct ExceptionValue<'ctx> {
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ExceptionValue<'ctx> {
|
||||||
|
/// Creates an [`ExceptionValue`] from a [`StructValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, llvm_usize, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`ExceptionValue`] from a [`PointerValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_value(
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
|
Self { value: ptr, llvm_usize, name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the ID of the exception name into this instance.
|
||||||
|
pub fn store_name(&self, ctx: &CodeGenContext<'ctx, '_>, name: IntValue<'ctx>) {
|
||||||
|
debug_assert_eq!(name.get_type(), ctx.ctx.i32_type());
|
||||||
|
|
||||||
|
self.name_field().store(ctx, self.value, name, self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().file
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the file name of the exception source into this instance.
|
||||||
|
pub fn store_file(&self, ctx: &CodeGenContext<'ctx, '_>, file: StructValue<'ctx>) {
|
||||||
|
debug_assert!(StringValue::is_instance(file, self.llvm_usize).is_ok());
|
||||||
|
|
||||||
|
self.file_field().store(ctx, self.value, file, self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().line
|
||||||
|
}
|
||||||
|
|
||||||
|
fn col_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().col
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the [location][Location] of the exception source into this instance.
|
||||||
|
pub fn store_location<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
location: Location,
|
||||||
|
) {
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
|
let filename = ctx.gen_string(generator, location.file.0);
|
||||||
|
self.store_file(ctx, filename);
|
||||||
|
|
||||||
|
self.line_field().store(
|
||||||
|
ctx,
|
||||||
|
self.value,
|
||||||
|
llvm_i32.const_int(location.row as u64, false),
|
||||||
|
self.name,
|
||||||
|
);
|
||||||
|
self.col_field().store(
|
||||||
|
ctx,
|
||||||
|
self.value,
|
||||||
|
llvm_i32.const_int(location.column as u64, false),
|
||||||
|
self.name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().func
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the function name of the exception source into this instance.
|
||||||
|
pub fn store_func(&self, ctx: &CodeGenContext<'ctx, '_>, func: StructValue<'ctx>) {
|
||||||
|
debug_assert!(StringValue::is_instance(func, self.llvm_usize).is_ok());
|
||||||
|
|
||||||
|
self.func_field().store(ctx, self.value, func, self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().message
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the exception message into this instance.
|
||||||
|
pub fn store_message(&self, ctx: &CodeGenContext<'ctx, '_>, message: StructValue<'ctx>) {
|
||||||
|
debug_assert!(StringValue::is_instance(message, self.llvm_usize).is_ok());
|
||||||
|
|
||||||
|
self.message_field().store(ctx, self.value, message, self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param0_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().param0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param1_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().param1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param2_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
|
self.get_type().get_fields().param2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the parameters of the exception into this instance.
|
||||||
|
///
|
||||||
|
/// If the parameter does not exist, pass `i64 0` in the parameter slot.
|
||||||
|
pub fn store_params(&self, ctx: &CodeGenContext<'ctx, '_>, params: &[IntValue<'ctx>; 3]) {
|
||||||
|
debug_assert!(params.iter().all(|p| p.get_type() == ctx.ctx.i64_type()));
|
||||||
|
|
||||||
|
[self.param0_field(), self.param1_field(), self.param2_field()]
|
||||||
|
.into_iter()
|
||||||
|
.zip_eq(params)
|
||||||
|
.for_each(|(field, param)| {
|
||||||
|
field.store(ctx, self.value, *param, self.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ProxyValue<'ctx> for ExceptionValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
|
type Base = PointerValue<'ctx>;
|
||||||
|
type Type = ExceptionType<'ctx>;
|
||||||
|
|
||||||
|
fn get_type(&self) -> Self::Type {
|
||||||
|
Self::Type::from_pointer_type(self.value.get_type(), self.llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_base_value(&self) -> Self::Base {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for ExceptionValue<'ctx> {}
|
||||||
|
|
||||||
|
impl<'ctx> From<ExceptionValue<'ctx>> for PointerValue<'ctx> {
|
||||||
|
fn from(value: ExceptionValue<'ctx>) -> Self {
|
||||||
|
value.as_base_value()
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ use inkwell::{types::IntType, values::BasicValue};
|
|||||||
|
|
||||||
use super::{types::ProxyType, CodeGenContext};
|
use super::{types::ProxyType, CodeGenContext};
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
|
pub use exception::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use option::*;
|
pub use option::*;
|
||||||
pub use range::*;
|
pub use range::*;
|
||||||
@ -9,6 +10,7 @@ pub use string::*;
|
|||||||
pub use tuple::*;
|
pub use tuple::*;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
mod exception;
|
||||||
mod list;
|
mod list;
|
||||||
pub mod ndarray;
|
pub mod ndarray;
|
||||||
mod option;
|
mod option;
|
||||||
|
Loading…
Reference in New Issue
Block a user