use alloc::vec::Vec;
use miden_assembly_syntax::{
Word,
ast::{InvocationTarget, InvokeKind},
diagnostics::Report,
};
use miden_core::{
mast::{CallNodeBuilder, DynNodeBuilder, MastForestContributor, MastNodeExt, MastNodeId},
operations::{AssemblyOp, Operation},
};
use smallvec::SmallVec;
use crate::{
Assembler, GlobalItemIndex, basic_block_builder::BasicBlockBuilder,
mast_forest_builder::MastForestBuilder,
};
impl Assembler {
pub(super) fn invoke(
&self,
kind: InvokeKind,
callee: &InvocationTarget,
caller: GlobalItemIndex,
mast_forest_builder: &mut MastForestBuilder,
before_enter: Vec<miden_core::mast::DecoratorId>,
asm_op: Option<AssemblyOp>,
) -> Result<MastNodeId, Report> {
let resolved = self
.resolve_target(kind, callee, caller, mast_forest_builder)?
.expect("invocation target is not a procedure");
match kind {
InvokeKind::ProcRef | InvokeKind::Exec => Ok(resolved.node),
InvokeKind::Call => mast_forest_builder.ensure_node_with_asm_op(
CallNodeBuilder::new(resolved.node)
.with_before_enter(before_enter)
.with_after_exit(vec![]),
asm_op.expect("call invocations must provide an AssemblyOp"),
),
InvokeKind::SysCall => mast_forest_builder.ensure_node_with_asm_op(
CallNodeBuilder::new_syscall(resolved.node)
.with_before_enter(before_enter)
.with_after_exit(vec![]),
asm_op.expect("syscall invocations must provide an AssemblyOp"),
),
}
}
pub(super) fn dynexec(
&self,
mast_forest_builder: &mut MastForestBuilder,
before_enter: Vec<miden_core::mast::DecoratorId>,
asm_op: AssemblyOp,
) -> Result<Option<MastNodeId>, Report> {
let dyn_node_id = mast_forest_builder.ensure_node_with_asm_op(
DynNodeBuilder::new_dyn()
.with_before_enter(before_enter)
.with_after_exit(vec![]),
asm_op,
)?;
Ok(Some(dyn_node_id))
}
pub(super) fn dyncall(
&self,
mast_forest_builder: &mut MastForestBuilder,
before_enter: Vec<miden_core::mast::DecoratorId>,
asm_op: AssemblyOp,
) -> Result<Option<MastNodeId>, Report> {
let dyn_call_node_id = mast_forest_builder.ensure_node_with_asm_op(
DynNodeBuilder::new_dyncall()
.with_before_enter(before_enter)
.with_after_exit(vec![]),
asm_op,
)?;
Ok(Some(dyn_call_node_id))
}
pub(super) fn procref(
&self,
callee: &InvocationTarget,
caller: GlobalItemIndex,
block_builder: &mut BasicBlockBuilder,
) -> Result<(), Report> {
let mast_root = {
let resolved = self
.resolve_target(
InvokeKind::ProcRef,
callee,
caller,
block_builder.mast_forest_builder_mut(),
)?
.expect("invocation target is not a procedure");
block_builder
.mast_forest_builder()
.get_mast_node(resolved.node)
.unwrap()
.digest()
};
self.procref_mast_root(mast_root, block_builder)
}
fn procref_mast_root(
&self,
mast_root: Word,
block_builder: &mut BasicBlockBuilder,
) -> Result<(), Report> {
let ops = mast_root
.iter()
.rev()
.map(|elem| Operation::Push(*elem))
.collect::<SmallVec<[_; 4]>>();
block_builder.push_ops(ops);
Ok(())
}
}