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
9pub 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 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}