use amplify::confinement::{self, TinyOrdSet};
use super::{Lib, LibId, MarshallError, Marshaller};
use crate::isa::{BytecodeRead, CodeEofError, Instruction};
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Display, Error, From)]
#[display(inner)]
pub enum AssemblerError {
#[from]
Bytecode(MarshallError),
#[from]
LibSegOverflow(confinement::Error),
}
impl Lib {
pub fn assemble<Isa>(code: &[Isa]) -> Result<Lib, AssemblerError>
where Isa: Instruction<LibId> {
let call_sites = code.iter().filter_map(|instr| instr.external_ref());
let libs_segment = TinyOrdSet::try_from_iter(call_sites)?;
let mut writer = Marshaller::new(&libs_segment);
for instr in code.iter() {
instr.encode_instr(&mut writer)?;
}
let (code_segment, data_segment) = writer.finish();
Ok(Lib {
isae: Isa::isa_ext(),
libs: libs_segment,
code: code_segment,
data: data_segment,
})
}
pub fn disassemble<Isa>(&self) -> Result<Vec<Isa>, CodeEofError>
where Isa: Instruction<LibId> {
let mut code = Vec::new();
let mut reader = Marshaller::with(&self.code, &self.data, &self.libs);
while !reader.is_eof() {
code.push(Isa::decode_instr(&mut reader)?);
}
Ok(code)
}
pub fn print_disassemble<Isa>(
&self,
mut writer: impl std::io::Write,
) -> Result<(), std::io::Error>
where
Isa: Instruction<LibId>,
{
let mut reader = Marshaller::with(&self.code, &self.data, &self.libs);
while !reader.is_eof() {
let pos = reader.offset().0 as usize;
write!(writer, "offset {pos:06}: ")?;
match Isa::decode_instr(&mut reader) {
Ok(instr) => writeln!(writer, "{instr}")?,
Err(_) => writeln!(writer, "; <incomplete instruction>")?,
}
}
Ok(())
}
}