aluvm/library/assembler.rs
1// Reference rust implementation of AluVM (arithmetic logic unit virtual machine).
2// To find more on AluVM please check <https://aluvm.org>
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Designed in 2021-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7// Written in 2021-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
8//
9// Copyright (C) 2021-2024 LNP/BP Standards Association, Switzerland.
10// Copyright (C) 2024-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
11// Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
12// Copyright (C) 2021-2025 Dr Maxim Orlovsky.
13// All rights under the above copyrights are reserved.
14//
15// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
16// in compliance with the License. You may obtain a copy of the License at
17//
18// http://www.apache.org/licenses/LICENSE-2.0
19//
20// Unless required by applicable law or agreed to in writing, software distributed under the License
21// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
22// or implied. See the License for the specific language governing permissions and limitations under
23// the License.
24
25use amplify::confinement::{self, TinyOrdSet};
26
27use super::{Lib, LibId, MarshallError, Marshaller};
28use crate::isa::{BytecodeRead, CodeEofError, Instruction};
29
30/// Errors while assembling lib-old from the instruction set.
31#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Display, Error, From)]
32#[display(inner)]
33pub enum AssemblerError {
34 /// Error assembling code and data segments.
35 #[from]
36 Bytecode(MarshallError),
37
38 /// Error assembling a library segment.
39 #[from]
40 LibSegOverflow(confinement::Error),
41}
42
43impl Lib {
44 /// Assembles a library from the provided instructions by encoding them into bytecode.
45 pub fn assemble<Isa>(code: &[Isa]) -> Result<Lib, AssemblerError>
46 where Isa: Instruction<LibId> {
47 let call_sites = code.iter().filter_map(|instr| instr.external_ref());
48 let libs_segment = TinyOrdSet::try_from_iter(call_sites)?;
49
50 let mut writer = Marshaller::new(&libs_segment);
51 for instr in code.iter() {
52 instr.encode_instr(&mut writer)?;
53 }
54 let (code_segment, data_segment) = writer.finish();
55
56 Ok(Lib {
57 isae: Isa::isa_ext(),
58 libs: libs_segment,
59 code: code_segment,
60 data: data_segment,
61 })
62 }
63
64 /// Disassembles the library into a set of instructions.
65 pub fn disassemble<Isa>(&self) -> Result<Vec<Isa>, CodeEofError>
66 where Isa: Instruction<LibId> {
67 let mut code = Vec::new();
68 let mut reader = Marshaller::with(&self.code, &self.data, &self.libs);
69 while !reader.is_eof() {
70 code.push(Isa::decode_instr(&mut reader)?);
71 }
72 Ok(code)
73 }
74
75 /// Disassembles the library into a set of instructions and offsets and prints it to the writer.
76 pub fn print_disassemble<Isa>(
77 &self,
78 mut writer: impl std::io::Write,
79 ) -> Result<(), std::io::Error>
80 where
81 Isa: Instruction<LibId>,
82 {
83 let mut reader = Marshaller::with(&self.code, &self.data, &self.libs);
84 while !reader.is_eof() {
85 let pos = reader.offset().0 as usize;
86 write!(writer, "offset {pos:06}: ")?;
87 match Isa::decode_instr(&mut reader) {
88 Ok(instr) => writeln!(writer, "{instr}")?,
89 Err(_) => writeln!(writer, "; <incomplete instruction>")?,
90 }
91 }
92 Ok(())
93 }
94}