openvm_transpiler/
transpiler.rs1use std::rc::Rc;
2
3use eyre::Report;
4use openvm_instructions::{exe::SparseMemoryImage, instruction::Instruction};
5use openvm_stark_backend::p3_field::PrimeField32;
6use thiserror::Error;
7
8use crate::TranspilerExtension;
9
10#[derive(Clone)]
13pub struct Transpiler<F> {
14 processors: Vec<Rc<dyn TranspilerExtension<F>>>,
15}
16
17impl<F: PrimeField32> Default for Transpiler<F> {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23#[derive(Error, Debug)]
24pub enum TranspilerError {
25 #[error("ambiguous next instruction")]
26 AmbiguousNextInstruction,
27 #[error("couldn't parse the next instruction: {0:032b}")]
28 ParseError(u32),
29 #[error("processor {processor_index} failed to modify initial memory")]
30 ModifyInitialMemoryFailed {
31 processor_index: usize,
32 #[source]
33 source: Report,
34 },
35}
36
37impl<F: PrimeField32> Transpiler<F> {
38 pub fn new() -> Self {
39 Self { processors: vec![] }
40 }
41
42 pub fn with_processor(self, proc: Rc<dyn TranspilerExtension<F>>) -> Self {
43 let mut procs = self.processors;
44 procs.push(proc);
45 Self { processors: procs }
46 }
47
48 pub fn with_extension<T: TranspilerExtension<F> + 'static>(self, ext: T) -> Self {
49 self.with_processor(Rc::new(ext))
50 }
51
52 pub fn transpile(
59 &self,
60 instructions_u32: &[u32],
61 ) -> Result<Vec<Option<Instruction<F>>>, TranspilerError> {
62 let mut instructions = Vec::new();
63 let mut ptr = 0;
64 while ptr < instructions_u32.len() {
65 let mut options = self
66 .processors
67 .iter()
68 .map(|proc| proc.process_custom(&instructions_u32[ptr..]))
69 .filter(|opt| opt.is_some())
70 .collect::<Vec<_>>();
71 if options.is_empty() {
72 return Err(TranspilerError::ParseError(instructions_u32[ptr]));
73 }
74 if options.len() > 1 {
75 return Err(TranspilerError::AmbiguousNextInstruction);
76 }
77 let transpiler_output = options.pop().unwrap().unwrap();
78 instructions.extend(transpiler_output.instructions);
79 ptr += transpiler_output.used_u32s;
80 }
81 Ok(instructions)
82 }
83
84 pub fn modify_initial_memory(
86 &self,
87 init_memory: &mut SparseMemoryImage,
88 ) -> Result<(), TranspilerError> {
89 for (i, processor) in self.processors.iter().enumerate() {
90 processor
91 .modify_initial_memory(init_memory)
92 .map_err(|source| TranspilerError::ModifyInitialMemoryFailed {
93 processor_index: i,
94 source,
95 })?;
96 }
97 Ok(())
98 }
99}