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