openvm_transpiler/
transpiler.rs

1use std::rc::Rc;
2
3use openvm_instructions::instruction::Instruction;
4use openvm_stark_backend::p3_field::PrimeField32;
5use thiserror::Error;
6
7use crate::TranspilerExtension;
8
9/// Collection of [`TranspilerExtension`]s.
10/// The transpiler can be configured to transpile any ELF in 32-bit chunks.
11pub struct Transpiler<F> {
12    processors: Vec<Rc<dyn TranspilerExtension<F>>>,
13}
14
15impl<F: PrimeField32> Default for Transpiler<F> {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21#[derive(Error, Debug)]
22pub enum TranspilerError {
23    #[error("ambiguous next instruction")]
24    AmbiguousNextInstruction,
25    #[error("couldn't parse the next instruction: {0:032b}")]
26    ParseError(u32),
27}
28
29impl<F: PrimeField32> Transpiler<F> {
30    pub fn new() -> Self {
31        Self { processors: vec![] }
32    }
33
34    pub fn with_processor(self, proc: Rc<dyn TranspilerExtension<F>>) -> Self {
35        let mut procs = self.processors;
36        procs.push(proc);
37        Self { processors: procs }
38    }
39
40    pub fn with_extension<T: TranspilerExtension<F> + 'static>(self, ext: T) -> Self {
41        self.with_processor(Rc::new(ext))
42    }
43
44    /// Iterates over a sequence of 32-bit RISC-V instructions `instructions_u32`. The iterator
45    /// applies every processor in the [`Transpiler`] to determine if one of them knows how to transpile
46    /// the current instruction (and possibly a contiguous section of following instructions).
47    /// If so, it advances the iterator by the amount specified by the processor.
48    /// The transpiler will panic if two different processors claim to know how to transpile the same instruction
49    /// to avoid ambiguity.
50    pub fn transpile(
51        &self,
52        instructions_u32: &[u32],
53    ) -> Result<Vec<Option<Instruction<F>>>, TranspilerError> {
54        let mut instructions = Vec::new();
55        let mut ptr = 0;
56        while ptr < instructions_u32.len() {
57            let mut options = self
58                .processors
59                .iter()
60                .map(|proc| proc.process_custom(&instructions_u32[ptr..]))
61                .filter(|opt| opt.is_some())
62                .collect::<Vec<_>>();
63            if options.is_empty() {
64                return Err(TranspilerError::ParseError(instructions_u32[ptr]));
65            }
66            if options.len() > 1 {
67                return Err(TranspilerError::AmbiguousNextInstruction);
68            }
69            let transpiler_output = options.pop().unwrap().unwrap();
70            instructions.extend(transpiler_output.instructions);
71            ptr += transpiler_output.used_u32s;
72        }
73        Ok(instructions)
74    }
75}