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}