use crate::{
context::Context,
error::{Error, ErrorTy, Result},
value::{
BlockParamRef, BlockRef, BodyView, FunctionBody, FunctionId, FunctionRef, InstructionRef,
QCodeView, ValueId,
block::{BasicBlock, BlockId, EdgeData, EdgeId},
block_param::{BlockParam, BlockParamId},
insn::{Instruction, InstructionId, Mnemonic},
},
};
pub struct BodyMut<'a, 'str> {
pub fun: &'a mut FunctionBody<'str>,
pub shared: &'a crate::context::Shared<'str>,
pub interfaces:
&'a jstd::registry::Registry<FunctionId, crate::value::function::FunctionInterface<'str>>,
}
impl<'a, 'str> BodyMut<'a, 'str> {
pub fn new(
fun: &'a mut FunctionBody<'str>,
shared: &'a crate::context::Shared<'str>,
interfaces: &'a jstd::registry::Registry<
FunctionId,
crate::value::function::FunctionInterface<'str>,
>,
) -> Self {
Self {
fun,
shared,
interfaces,
}
}
pub fn from_ctx(fun: &'a mut FunctionBody<'str>, ctx: &'a Context<'str>) -> Self {
Self::new(fun, &ctx.shared, &ctx.interfaces)
}
pub fn reborrow(&mut self) -> BodyMut<'_, 'str> {
BodyMut {
fun: &mut *self.fun,
shared: self.shared,
interfaces: self.interfaces,
}
}
pub fn builder(&mut self, block: BlockId) -> crate::builder::Builder<'str, '_> {
crate::builder::Builder::new(&mut *self.fun, self.shared, self.interfaces, block)
}
}
impl<'a, 'str> BodyMut<'a, 'str> {
pub fn function_mut(&mut self, f: FunctionId) -> &mut FunctionBody<'str> {
assert_eq!(
f,
self.fun.id(),
"a checked-out function pass may not mutate another function"
);
self.fun
}
pub fn function(&self, f: FunctionId) -> &FunctionBody<'str> {
assert_eq!(
f,
self.fun.id(),
"a checked-out function pass may not read another function's arenas mutably"
);
self.fun
}
pub fn shr(&self) -> &crate::context::Shared<'str> {
self.shared
}
pub fn view(&self) -> BodyView<'_, 'str> {
BodyView::new(&*self.fun, self.shared, self.interfaces)
}
pub fn block_ref(&self, id: BlockId) -> BlockRef<'str, '_, BodyView<'_, 'str>> {
self.view().block_ref(id)
}
pub fn insn_ref(&self, id: InstructionId) -> InstructionRef<'str, '_, BodyView<'_, 'str>> {
self.view().insn_ref(id)
}
pub fn param_ref(&self, id: BlockParamId) -> BlockParamRef<'str, '_, BodyView<'_, 'str>> {
self.view().param_ref(id)
}
pub fn function_ref(&self, id: FunctionId) -> FunctionRef<'str, '_, BodyView<'_, 'str>> {
self.view().function_ref(id)
}
pub fn push_edge(&mut self, edge: EdgeData) -> EdgeId {
self.fun.edges.push(edge)
}
pub fn push_insn(&mut self, insn: Instruction<'str>) -> InstructionId {
self.fun.push_insn(insn)
}
pub fn push_block(&mut self, block: BasicBlock<'str>) -> BlockId {
self.fun.push_block(block)
}
pub fn make_block(&mut self) -> BlockId {
self.fun.make_block()
}
pub fn push_block_param(&mut self, param: BlockParam<'str>) -> BlockParamId {
self.fun.push_block_param(param)
}
pub fn push_mnemonic(&mut self, mnemonic: Mnemonic, size: usize) -> InstructionId {
let shared = self.shared;
self.fun.push_mnemonic(shared, mnemonic, size)
}
pub fn push_mnemonic_with_type(
&mut self,
mnemonic: Mnemonic,
type_id: crate::types::TypeId,
) -> InstructionId {
self.fun.push_mnemonic_with_type(mnemonic, type_id)
}
pub fn remove_cfg_edge(&mut self, edge_id: EdgeId) {
self.fun.remove_cfg_edge(edge_id)
}
pub fn register_local_name(
&mut self,
id: ValueId,
name: std::borrow::Cow<'str, str>,
old_name: Option<&str>,
) -> Result<()> {
let existing = match id.name_scope_function() {
Some(func) => self
.function(func)
.names
.get(&name)
.map(|id| id.qualify(func)),
None => self.shr().get_named(&name),
};
if let Some(existing) = existing {
return if existing == id {
Ok(())
} else {
Err(Error::spanless(ErrorTy::DuplicateName(name.to_string())))
};
}
match id.name_scope_function() {
Some(func) => self
.function_mut(func)
.names
.register(name, id.localize(func), old_name),
None => {
unimplemented!("a checked-out host has read-only shared access (mints via &self)")
}
}
}
}