forked from M-Labs/nac3
core: split codegen optics into modules
This commit is contained in:
parent
9a82b033b6
commit
e4998ccec8
|
@ -1,9 +1,7 @@
|
|||
use inkwell::types::IntType;
|
||||
|
||||
use crate::codegen::{
|
||||
optics::{Address, AddressLens, ArraySlice, FieldBuilder, GepGetter, IntLens, StructureOptic},
|
||||
CodeGenContext,
|
||||
};
|
||||
use crate::codegen::optics::*;
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StrLens<'ctx> {
|
||||
|
@ -51,10 +49,7 @@ impl<'ctx> StructureOptic<'ctx> for NpArrayLens<'ctx> {
|
|||
"NDArray"
|
||||
}
|
||||
|
||||
fn build_fields(
|
||||
&self,
|
||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
||||
) -> Self::Fields {
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||
NpArrayFields {
|
||||
data: builder.add_field("data", AddressLens(IntLens(builder.ctx.i8_type()))),
|
||||
itemsize: builder.add_field("itemsize", IntLens(builder.ctx.i8_type())),
|
||||
|
@ -96,10 +91,7 @@ impl<'ctx> StructureOptic<'ctx> for IrrtStringLens {
|
|||
"String"
|
||||
}
|
||||
|
||||
fn build_fields(
|
||||
&self,
|
||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
||||
) -> Self::Fields {
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||
let llvm_i8 = builder.ctx.i8_type();
|
||||
let llvm_i32 = builder.ctx.i32_type();
|
||||
IrrtStringFields {
|
||||
|
@ -157,10 +149,7 @@ impl<'ctx> StructureOptic<'ctx> for ErrorContextLens {
|
|||
"ErrorContext"
|
||||
}
|
||||
|
||||
fn build_fields(
|
||||
&self,
|
||||
builder: &mut crate::codegen::optics::FieldBuilder<'ctx>,
|
||||
) -> Self::Fields {
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields {
|
||||
ErrorContextFields {
|
||||
error_ids: builder.add_field("error_ids", AddressLens(ErrorIdsLens)),
|
||||
error_id: builder.add_field("error_id", IntLens(builder.ctx.i32_type())),
|
||||
|
|
|
@ -4,7 +4,11 @@ use inkwell::{
|
|||
};
|
||||
|
||||
use crate::codegen::{
|
||||
optics::{Address, AddressLens, IntLens, Optic, OpticValue, Prism},
|
||||
optics::{
|
||||
address::{Address, AddressLens},
|
||||
core::{Optic, OpticValue, Prism},
|
||||
int::IntLens,
|
||||
},
|
||||
CodeGenContext, CodeGenerator,
|
||||
};
|
||||
use crate::util::SizeVariant;
|
||||
|
|
|
@ -5,10 +5,10 @@ use inkwell::{
|
|||
values::{BasicValueEnum, IntValue},
|
||||
};
|
||||
|
||||
use crate::codegen::optics::*;
|
||||
use crate::{
|
||||
codegen::{
|
||||
classes::{ListValue, UntypedArrayLikeAccessor},
|
||||
optics::{opaque_address_lens, Address, AddressLens, ArraySlice, IntLens, Ixed, Optic},
|
||||
stmt::gen_for_callback_incrementing,
|
||||
CodeGenContext, CodeGenerator,
|
||||
},
|
||||
|
|
|
@ -26,7 +26,7 @@ use inkwell::{
|
|||
use irrt::classes::StrLens;
|
||||
use itertools::Itertools;
|
||||
use nac3parser::ast::{Location, Stmt, StrRef};
|
||||
use optics::Optic;
|
||||
use optics::Optic as _;
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{
|
||||
|
|
|
@ -1,449 +0,0 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::{BasicType, BasicTypeEnum, IntType},
|
||||
values::{AnyValue, BasicValue, BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||
AddressSpace,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::{CodeGenContext, CodeGenerator};
|
||||
|
||||
// TODO: Write a taxonomy
|
||||
|
||||
pub trait OpticValue<'ctx> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx>;
|
||||
}
|
||||
|
||||
impl<'ctx, T: BasicValue<'ctx>> OpticValue<'ctx> for T {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The interface is unintuitive
|
||||
pub trait Optic<'ctx>: Clone {
|
||||
type Value: OpticValue<'ctx>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
||||
|
||||
fn alloca(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> Address<'ctx, Self> {
|
||||
let ptr = ctx.builder.build_alloca(self.get_llvm_type(ctx.ctx), name).unwrap();
|
||||
Address { addressee_optic: self.clone(), address: ptr }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Prism<'ctx>: Optic<'ctx> {
|
||||
// TODO: Return error if `review` fails
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value;
|
||||
}
|
||||
|
||||
pub trait MemoryGetter<'ctx>: Optic<'ctx> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value;
|
||||
}
|
||||
|
||||
pub trait MemorySetter<'ctx>: Optic<'ctx> {
|
||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::Value);
|
||||
}
|
||||
|
||||
// NOTE: I wanted to make Int8Lens, Int16Lens, Int32Lens, with all
|
||||
// having the trait IsIntLens, and implement `impl <S: IsIntLens> Optic<S> for T`,
|
||||
// but that clashes with StructureOptic!!
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IntLens<'ctx>(pub IntType<'ctx>);
|
||||
|
||||
impl<'ctx> IntLens<'ctx> {
|
||||
#[must_use]
|
||||
pub fn int8(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i8_type())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn int32(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i32_type())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn int64(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i64_type())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
|
||||
type Value = IntValue<'ctx>;
|
||||
|
||||
fn get_llvm_type(&self, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.0.as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Prism<'ctx> for IntLens<'ctx> {
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||
let int = value.as_any_value_enum().into_int_value();
|
||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||
int
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> MemoryGetter<'ctx> for IntLens<'ctx> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> MemorySetter<'ctx> for IntLens<'ctx> {
|
||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, int: &Self::Value) {
|
||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||
ctx.builder.build_store(pointer, int.as_basic_value_enum()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Address<'ctx, AddresseeOptic> {
|
||||
pub addressee_optic: AddresseeOptic,
|
||||
pub address: PointerValue<'ctx>,
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
|
||||
pub fn cast_to<S: Optic<'ctx>>(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
new_optic: S,
|
||||
) -> Address<'ctx, S> {
|
||||
let to_ptr_type = new_optic.get_llvm_type(ctx.ctx).ptr_type(AddressSpace::default());
|
||||
let casted_address =
|
||||
ctx.builder.build_pointer_cast(self.address, to_ptr_type, "ptr_casted").unwrap();
|
||||
Address { addressee_optic: new_optic, address: casted_address }
|
||||
}
|
||||
|
||||
pub fn cast_to_opaque(&self, ctx: &CodeGenContext<'ctx, '_>) -> Address<'ctx, IntLens<'ctx>> {
|
||||
self.cast_to(ctx, IntLens::int8(ctx.ctx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.address.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
||||
|
||||
#[must_use]
|
||||
pub fn opaque_address_lens(ctx: &Context) -> AddressLens<IntLens<'_>> {
|
||||
AddressLens(IntLens::int8(ctx))
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
||||
type Value = Address<'ctx, AddresseeOptic>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.0.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOptic> {
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||
Address {
|
||||
addressee_optic: self.0.clone(),
|
||||
address: value.as_any_value_enum().into_pointer_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
|
||||
fn set(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
value: &Self::Value,
|
||||
) {
|
||||
ctx.builder.build_store(pointer, value.address).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// To make [`Address`] convenient to use
|
||||
impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn load(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> AddresseeOptic::Value {
|
||||
self.addressee_optic.get(ctx, self.address, name)
|
||||
}
|
||||
}
|
||||
|
||||
// To make [`Address`] convenient to use
|
||||
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
||||
self.addressee_optic.set(ctx, self.address, value);
|
||||
}
|
||||
}
|
||||
|
||||
// ((Memory, Pointer) -> ElementOptic::Value*)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GepGetter<ElementOptic> {
|
||||
/// The LLVM GEP index
|
||||
pub gep_index: u64,
|
||||
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
||||
pub name: &'static str,
|
||||
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
||||
pub element_optic: ElementOptic,
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> Optic<'ctx> for GepGetter<ElementOptic> {
|
||||
type Value = Address<'ctx, ElementOptic>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.element_optic.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOptic> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
let llvm_i32 = ctx.ctx.i32_type(); // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
||||
let element_ptr = unsafe {
|
||||
ctx.builder
|
||||
.build_in_bounds_gep(
|
||||
pointer,
|
||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
||||
name,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
Address { address: element_ptr, addressee_optic: self.element_optic.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
// Only used by [`FieldBuilder`]
|
||||
#[derive(Debug)]
|
||||
struct FieldInfo<'ctx> {
|
||||
gep_index: u64,
|
||||
name: &'ctx str,
|
||||
llvm_type: BasicTypeEnum<'ctx>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldBuilder<'ctx> {
|
||||
pub ctx: &'ctx Context,
|
||||
gep_index_counter: u64,
|
||||
struct_name: &'ctx str,
|
||||
fields: Vec<FieldInfo<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> FieldBuilder<'ctx> {
|
||||
#[must_use]
|
||||
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
||||
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
||||
}
|
||||
|
||||
fn next_gep_index(&mut self) -> u64 {
|
||||
let index = self.gep_index_counter;
|
||||
self.gep_index_counter += 1;
|
||||
index
|
||||
}
|
||||
|
||||
pub fn add_field<ElementOptic: Optic<'ctx>>(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
element_optic: ElementOptic,
|
||||
) -> GepGetter<ElementOptic> {
|
||||
let gep_index = self.next_gep_index();
|
||||
|
||||
self.fields.push(FieldInfo {
|
||||
gep_index,
|
||||
name,
|
||||
llvm_type: element_optic.get_llvm_type(self.ctx),
|
||||
});
|
||||
|
||||
GepGetter { gep_index, name, element_optic }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StructureOptic<'ctx>: Clone {
|
||||
// Fields of optics
|
||||
type Fields;
|
||||
|
||||
// TODO: Make it an associated function instead?
|
||||
fn struct_name(&self) -> &'static str;
|
||||
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields;
|
||||
|
||||
fn get_fields(&self, ctx: &'ctx Context) -> Self::Fields {
|
||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||
self.build_fields(&mut builder)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpticalStructValue<'ctx, StructOptic> {
|
||||
optic: StructOptic,
|
||||
llvm: StructValue<'ctx>,
|
||||
}
|
||||
|
||||
impl<'ctx, StructOptic> OpticValue<'ctx> for OpticalStructValue<'ctx, StructOptic> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.llvm.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check StructType
|
||||
impl<'ctx, T: StructureOptic<'ctx>> Optic<'ctx> for T {
|
||||
type Value = OpticalStructValue<'ctx, Self>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||
self.build_fields(&mut builder); // Self::Fields is discarded
|
||||
|
||||
let field_types =
|
||||
builder.fields.iter().map(|field_info| field_info.llvm_type).collect_vec();
|
||||
ctx.struct_type(&field_types, false).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, T: StructureOptic<'ctx>> MemoryGetter<'ctx> for T {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
OpticalStructValue {
|
||||
optic: self.clone(),
|
||||
llvm: ctx.builder.build_load(pointer, name).unwrap().into_struct_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, T: StructureOptic<'ctx>> MemorySetter<'ctx> for T {
|
||||
fn set(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
value: &Self::Value,
|
||||
) {
|
||||
ctx.builder.build_store(pointer, value.llvm).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn focus<GetFieldGepFn, FieldElementOptic: Optic<'ctx>>(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
get_field_gep_fn: GetFieldGepFn,
|
||||
) -> Address<'ctx, FieldElementOptic>
|
||||
where
|
||||
GetFieldGepFn: FnOnce(&AddresseeOptic::Fields) -> &GepGetter<FieldElementOptic>,
|
||||
{
|
||||
let fields = self.addressee_optic.get_fields(ctx.ctx);
|
||||
let field = get_field_gep_fn(&fields);
|
||||
field.get(ctx, self.address, field.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Name inspired by https://hackage.haskell.org/package/lens-5.3.2/docs/Control-Lens-At.html#t:Ixed
|
||||
pub trait Ixed<'ctx, ElementOptic> {
|
||||
// TODO: Interface/Method to expose the IntType of index?
|
||||
// or even make index itself parameterized? (probably no)
|
||||
|
||||
fn ix(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic>;
|
||||
}
|
||||
|
||||
// TODO: Can do interface seggregation
|
||||
pub trait BoundedIxed<'ctx, ElementOptic>: Ixed<'ctx, ElementOptic> {
|
||||
fn num_elements(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx>;
|
||||
|
||||
// Check if 0 <= index < self.num_elements()
|
||||
fn ix_bounds_checked<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic> {
|
||||
let num_elements = self.num_elements(ctx);
|
||||
let int_type = num_elements.get_type(); // NOTE: Weird get_type(), see comment under `trait Ixed`
|
||||
|
||||
assert_eq!(int_type.get_bit_width(), index.get_type().get_bit_width()); // Might as well check bit width to catch bugs
|
||||
|
||||
// TODO: SGE or UGE? or make it defined by the implementee?
|
||||
|
||||
// Check `0 <= index`
|
||||
let lower_bounded = ctx
|
||||
.builder
|
||||
.build_int_compare(
|
||||
inkwell::IntPredicate::SLE,
|
||||
int_type.const_zero(),
|
||||
index,
|
||||
"lower_bounded",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Check `index < num_elements`
|
||||
let upper_bounded = ctx
|
||||
.builder
|
||||
.build_int_compare(inkwell::IntPredicate::SLT, index, num_elements, "upper_bounded")
|
||||
.unwrap();
|
||||
|
||||
// Compute `0 <= index && index < num_elements`
|
||||
let bounded = ctx.builder.build_and(lower_bounded, upper_bounded, "bounded").unwrap();
|
||||
|
||||
// Assert `bounded`
|
||||
ctx.make_assert(generator, bounded, "0:IndexError", "nac3core LLVM codegen attempting to access out of bounds array index {0}. Must satisfy 0 <= index < {2}", [Some(index), Some(num_elements), None], ctx.current_loc);
|
||||
|
||||
// ...and finally do indexing
|
||||
self.ix(ctx, index, name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ArraySlice<'ctx, ElementOptic> {
|
||||
pub num_elements: IntValue<'ctx>,
|
||||
pub base: Address<'ctx, ElementOptic>,
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
|
||||
fn ix(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic> {
|
||||
let element_addr =
|
||||
unsafe { ctx.builder.build_in_bounds_gep(self.base.address, &[index], name).unwrap() };
|
||||
Address { address: element_addr, addressee_optic: self.base.addressee_optic.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> BoundedIxed<'ctx, ElementOptic>
|
||||
for ArraySlice<'ctx, ElementOptic>
|
||||
{
|
||||
fn num_elements(&self, _ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||
self.num_elements
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::{BasicType, BasicTypeEnum},
|
||||
values::{AnyValue, BasicValue, BasicValueEnum, PointerValue},
|
||||
AddressSpace,
|
||||
};
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::{
|
||||
core::{MemoryGetter, MemorySetter, Optic, OpticValue, Prism},
|
||||
int::IntLens,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Address<'ctx, AddresseeOptic> {
|
||||
pub addressee_optic: AddresseeOptic,
|
||||
pub address: PointerValue<'ctx>,
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic> Address<'ctx, AddresseeOptic> {
|
||||
pub fn cast_to<S: Optic<'ctx>>(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
new_optic: S,
|
||||
) -> Address<'ctx, S> {
|
||||
let to_ptr_type = new_optic.get_llvm_type(ctx.ctx).ptr_type(AddressSpace::default());
|
||||
let casted_address =
|
||||
ctx.builder.build_pointer_cast(self.address, to_ptr_type, "ptr_casted").unwrap();
|
||||
Address { addressee_optic: new_optic, address: casted_address }
|
||||
}
|
||||
|
||||
pub fn cast_to_opaque(&self, ctx: &CodeGenContext<'ctx, '_>) -> Address<'ctx, IntLens<'ctx>> {
|
||||
self.cast_to(ctx, IntLens::int8(ctx.ctx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic> OpticValue<'ctx> for Address<'ctx, AddresseeOptic> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.address.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AddressLens<AddresseeOptic>(pub AddresseeOptic);
|
||||
|
||||
#[must_use]
|
||||
pub fn opaque_address_lens(ctx: &Context) -> AddressLens<IntLens<'_>> {
|
||||
AddressLens(IntLens::int8(ctx))
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Optic<'ctx> for AddressLens<AddresseeOptic> {
|
||||
type Value = Address<'ctx, AddresseeOptic>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.0.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: Optic<'ctx>> Prism<'ctx> for AddressLens<AddresseeOptic> {
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||
Address {
|
||||
addressee_optic: self.0.clone(),
|
||||
address: value.as_any_value_enum().into_pointer_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemoryGetter<'ctx> for AddressLens<AddressesOptic> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddressesOptic: Optic<'ctx>> MemorySetter<'ctx> for AddressLens<AddressesOptic> {
|
||||
fn set(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
value: &Self::Value,
|
||||
) {
|
||||
ctx.builder.build_store(pointer, value.address).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// To make [`Address`] convenient to use
|
||||
impl<'ctx, AddresseeOptic: MemoryGetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn load(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> AddresseeOptic::Value {
|
||||
self.addressee_optic.get(ctx, self.address, name)
|
||||
}
|
||||
}
|
||||
|
||||
// To make [`Address`] convenient to use
|
||||
impl<'ctx, AddresseeOptic: MemorySetter<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn store(&self, ctx: &CodeGenContext<'ctx, '_>, value: &AddresseeOptic::Value) {
|
||||
self.addressee_optic.set(ctx, self.address, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::BasicTypeEnum,
|
||||
values::{AnyValue, BasicValue, BasicValueEnum, PointerValue},
|
||||
};
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::address::Address;
|
||||
|
||||
// TODO: Write a taxonomy
|
||||
|
||||
pub trait OpticValue<'ctx> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx>;
|
||||
}
|
||||
|
||||
impl<'ctx, T: BasicValue<'ctx>> OpticValue<'ctx> for T {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The interface is unintuitive
|
||||
pub trait Optic<'ctx>: Clone {
|
||||
type Value: OpticValue<'ctx>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
||||
|
||||
fn alloca(&self, ctx: &CodeGenContext<'ctx, '_>, name: &str) -> Address<'ctx, Self> {
|
||||
let ptr = ctx.builder.build_alloca(self.get_llvm_type(ctx.ctx), name).unwrap();
|
||||
Address { addressee_optic: self.clone(), address: ptr }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Prism<'ctx>: Optic<'ctx> {
|
||||
// TODO: Return error if `review` fails
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value;
|
||||
}
|
||||
|
||||
pub trait MemoryGetter<'ctx>: Optic<'ctx> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value;
|
||||
}
|
||||
|
||||
pub trait MemorySetter<'ctx>: Optic<'ctx> {
|
||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, value: &Self::Value);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::{BasicType, BasicTypeEnum},
|
||||
values::PointerValue,
|
||||
AddressSpace,
|
||||
};
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::{
|
||||
address::Address,
|
||||
core::{MemoryGetter, Optic},
|
||||
};
|
||||
|
||||
// ((Memory, Pointer) -> ElementOptic::Value*)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GepGetter<ElementOptic> {
|
||||
/// The LLVM GEP index
|
||||
pub gep_index: u64,
|
||||
/// Element (or field in the context of `struct`s) name. Used for cosmetics.
|
||||
pub name: &'static str,
|
||||
/// The lens to view the actual value after applying this [`FieldLens<T>`]
|
||||
pub element_optic: ElementOptic,
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> Optic<'ctx> for GepGetter<ElementOptic> {
|
||||
type Value = Address<'ctx, ElementOptic>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.element_optic.get_llvm_type(ctx).ptr_type(AddressSpace::default()).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> MemoryGetter<'ctx> for GepGetter<ElementOptic> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
let llvm_i32 = ctx.ctx.i32_type(); // TODO: I think I'm not supposed to *just* use i32 for GEP like that
|
||||
let element_ptr = unsafe {
|
||||
ctx.builder
|
||||
.build_in_bounds_gep(
|
||||
pointer,
|
||||
&[llvm_i32.const_zero(), llvm_i32.const_int(self.gep_index, false)],
|
||||
name,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
Address { address: element_ptr, addressee_optic: self.element_optic.clone() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::{BasicType, BasicTypeEnum, IntType},
|
||||
values::{AnyValue, BasicValue, IntValue, PointerValue},
|
||||
};
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::core::{MemoryGetter, MemorySetter, Optic, Prism};
|
||||
|
||||
// NOTE: I wanted to make Int8Lens, Int16Lens, Int32Lens, with all
|
||||
// having the trait IsIntLens, and implement `impl <S: IsIntLens> Optic<S> for T`,
|
||||
// but that clashes with StructureOptic!!
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IntLens<'ctx>(pub IntType<'ctx>);
|
||||
|
||||
impl<'ctx> IntLens<'ctx> {
|
||||
#[must_use]
|
||||
pub fn int8(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i8_type())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn int32(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i32_type())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn int64(ctx: &'ctx Context) -> IntLens<'ctx> {
|
||||
IntLens(ctx.i64_type())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Optic<'ctx> for IntLens<'ctx> {
|
||||
type Value = IntValue<'ctx>;
|
||||
|
||||
fn get_llvm_type(&self, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
self.0.as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Prism<'ctx> for IntLens<'ctx> {
|
||||
fn review<V: AnyValue<'ctx>>(&self, value: V) -> Self::Value {
|
||||
let int = value.as_any_value_enum().into_int_value();
|
||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||
int
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> MemoryGetter<'ctx> for IntLens<'ctx> {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
self.review(ctx.builder.build_load(pointer, name).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> MemorySetter<'ctx> for IntLens<'ctx> {
|
||||
fn set(&self, ctx: &CodeGenContext<'ctx, '_>, pointer: PointerValue<'ctx>, int: &Self::Value) {
|
||||
debug_assert_eq!(int.get_type().get_bit_width(), self.0.get_bit_width());
|
||||
ctx.builder.build_store(pointer, int.as_basic_value_enum()).unwrap();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
use inkwell::values::IntValue;
|
||||
|
||||
use crate::codegen::{CodeGenContext, CodeGenerator};
|
||||
|
||||
use super::address::Address;
|
||||
|
||||
// Name inspired by https://hackage.haskell.org/package/lens-5.3.2/docs/Control-Lens-At.html#t:Ixed
|
||||
pub trait Ixed<'ctx, ElementOptic> {
|
||||
// TODO: Interface/Method to expose the IntType of index?
|
||||
// or even make index itself parameterized? (probably no)
|
||||
|
||||
fn ix(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic>;
|
||||
}
|
||||
|
||||
// TODO: Can do interface seggregation
|
||||
pub trait BoundedIxed<'ctx, ElementOptic>: Ixed<'ctx, ElementOptic> {
|
||||
fn num_elements(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx>;
|
||||
|
||||
// Check if 0 <= index < self.num_elements()
|
||||
fn ix_bounds_checked<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic> {
|
||||
let num_elements = self.num_elements(ctx);
|
||||
let int_type = num_elements.get_type(); // NOTE: Weird get_type(), see comment under `trait Ixed`
|
||||
|
||||
assert_eq!(int_type.get_bit_width(), index.get_type().get_bit_width()); // Might as well check bit width to catch bugs
|
||||
|
||||
// TODO: SGE or UGE? or make it defined by the implementee?
|
||||
|
||||
// Check `0 <= index`
|
||||
let lower_bounded = ctx
|
||||
.builder
|
||||
.build_int_compare(
|
||||
inkwell::IntPredicate::SLE,
|
||||
int_type.const_zero(),
|
||||
index,
|
||||
"lower_bounded",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Check `index < num_elements`
|
||||
let upper_bounded = ctx
|
||||
.builder
|
||||
.build_int_compare(inkwell::IntPredicate::SLT, index, num_elements, "upper_bounded")
|
||||
.unwrap();
|
||||
|
||||
// Compute `0 <= index && index < num_elements`
|
||||
let bounded = ctx.builder.build_and(lower_bounded, upper_bounded, "bounded").unwrap();
|
||||
|
||||
// Assert `bounded`
|
||||
ctx.make_assert(generator, bounded, "0:IndexError", "nac3core LLVM codegen attempting to access out of bounds array index {0}. Must satisfy 0 <= index < {2}", [Some(index), Some(num_elements), None], ctx.current_loc);
|
||||
|
||||
// ...and finally do indexing
|
||||
self.ix(ctx, index, name)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
pub mod address;
|
||||
pub mod core;
|
||||
pub mod gep;
|
||||
pub mod int;
|
||||
pub mod ixed;
|
||||
pub mod slice;
|
||||
pub mod structure;
|
||||
|
||||
pub use address::*;
|
||||
pub use core::*;
|
||||
pub use gep::*;
|
||||
pub use int::*;
|
||||
pub use ixed::*;
|
||||
pub use slice::*;
|
||||
pub use structure::*;
|
|
@ -0,0 +1,36 @@
|
|||
use super::{
|
||||
core::Optic,
|
||||
ixed::{BoundedIxed, Ixed},
|
||||
};
|
||||
|
||||
use inkwell::values::IntValue;
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::address::Address;
|
||||
|
||||
pub struct ArraySlice<'ctx, ElementOptic> {
|
||||
pub num_elements: IntValue<'ctx>,
|
||||
pub base: Address<'ctx, ElementOptic>,
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> Ixed<'ctx, ElementOptic> for ArraySlice<'ctx, ElementOptic> {
|
||||
fn ix(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Address<'ctx, ElementOptic> {
|
||||
let element_addr =
|
||||
unsafe { ctx.builder.build_in_bounds_gep(self.base.address, &[index], name).unwrap() };
|
||||
Address { address: element_addr, addressee_optic: self.base.addressee_optic.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, ElementOptic: Optic<'ctx>> BoundedIxed<'ctx, ElementOptic>
|
||||
for ArraySlice<'ctx, ElementOptic>
|
||||
{
|
||||
fn num_elements(&self, _ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||
self.num_elements
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
use inkwell::{
|
||||
context::Context,
|
||||
types::{BasicType, BasicTypeEnum},
|
||||
values::{BasicValue, BasicValueEnum, PointerValue, StructValue},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
use super::{
|
||||
address::Address,
|
||||
core::{MemoryGetter, MemorySetter, Optic, OpticValue},
|
||||
gep::GepGetter,
|
||||
};
|
||||
|
||||
pub trait StructureOptic<'ctx>: Clone {
|
||||
// Fields of optics
|
||||
type Fields;
|
||||
|
||||
// TODO: Make it an associated function instead?
|
||||
fn struct_name(&self) -> &'static str;
|
||||
|
||||
fn build_fields(&self, builder: &mut FieldBuilder<'ctx>) -> Self::Fields;
|
||||
|
||||
fn get_fields(&self, ctx: &'ctx Context) -> Self::Fields {
|
||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||
self.build_fields(&mut builder)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpticalStructValue<'ctx, StructOptic> {
|
||||
optic: StructOptic,
|
||||
llvm: StructValue<'ctx>,
|
||||
}
|
||||
|
||||
impl<'ctx, StructOptic> OpticValue<'ctx> for OpticalStructValue<'ctx, StructOptic> {
|
||||
fn get_llvm_value(&self) -> BasicValueEnum<'ctx> {
|
||||
self.llvm.as_basic_value_enum()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check StructType
|
||||
impl<'ctx, T: StructureOptic<'ctx>> Optic<'ctx> for T {
|
||||
type Value = OpticalStructValue<'ctx, Self>;
|
||||
|
||||
fn get_llvm_type(&self, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||
let mut builder = FieldBuilder::new(ctx, self.struct_name());
|
||||
self.build_fields(&mut builder); // Self::Fields is discarded
|
||||
|
||||
let field_types =
|
||||
builder.fields.iter().map(|field_info| field_info.llvm_type).collect_vec();
|
||||
ctx.struct_type(&field_types, false).as_basic_type_enum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, T: StructureOptic<'ctx>> MemoryGetter<'ctx> for T {
|
||||
fn get(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> Self::Value {
|
||||
OpticalStructValue {
|
||||
optic: self.clone(),
|
||||
llvm: ctx.builder.build_load(pointer, name).unwrap().into_struct_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, T: StructureOptic<'ctx>> MemorySetter<'ctx> for T {
|
||||
fn set(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
value: &Self::Value,
|
||||
) {
|
||||
ctx.builder.build_store(pointer, value.llvm).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, AddresseeOptic: StructureOptic<'ctx>> Address<'ctx, AddresseeOptic> {
|
||||
pub fn focus<GetFieldGepFn, FieldElementOptic: Optic<'ctx>>(
|
||||
&self,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
get_field_gep_fn: GetFieldGepFn,
|
||||
) -> Address<'ctx, FieldElementOptic>
|
||||
where
|
||||
GetFieldGepFn: FnOnce(&AddresseeOptic::Fields) -> &GepGetter<FieldElementOptic>,
|
||||
{
|
||||
let fields = self.addressee_optic.get_fields(ctx.ctx);
|
||||
let field = get_field_gep_fn(&fields);
|
||||
field.get(ctx, self.address, field.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Only used by [`FieldBuilder`]
|
||||
#[derive(Debug)]
|
||||
struct FieldInfo<'ctx> {
|
||||
gep_index: u64,
|
||||
name: &'ctx str,
|
||||
llvm_type: BasicTypeEnum<'ctx>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldBuilder<'ctx> {
|
||||
pub ctx: &'ctx Context,
|
||||
gep_index_counter: u64,
|
||||
struct_name: &'ctx str,
|
||||
fields: Vec<FieldInfo<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> FieldBuilder<'ctx> {
|
||||
#[must_use]
|
||||
pub fn new(ctx: &'ctx Context, struct_name: &'ctx str) -> Self {
|
||||
FieldBuilder { ctx, gep_index_counter: 0, struct_name, fields: Vec::new() }
|
||||
}
|
||||
|
||||
fn next_gep_index(&mut self) -> u64 {
|
||||
let index = self.gep_index_counter;
|
||||
self.gep_index_counter += 1;
|
||||
index
|
||||
}
|
||||
|
||||
pub fn add_field<ElementOptic: Optic<'ctx>>(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
element_optic: ElementOptic,
|
||||
) -> GepGetter<ElementOptic> {
|
||||
let gep_index = self.next_gep_index();
|
||||
|
||||
self.fields.push(FieldInfo {
|
||||
gep_index,
|
||||
name,
|
||||
llvm_type: element_optic.get_llvm_type(self.ctx),
|
||||
});
|
||||
|
||||
GepGetter { gep_index, name, element_optic }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue