libbf/runtime/
step_runner.rs

1///! Step-by-step program runner.
2use crate::prelude::ProgramIndex;
3
4use super::*;
5
6/// A step-by-step program runner.
7///
8/// This runner runs the program step-by-step.
9///
10/// It is useful for debugging, visual representation backend and etc,...
11pub struct StepRunner<'a, R, W> {
12    program: &'a Program,
13    runtime: internal::Runtime<R, W>,
14    index: Option<ProgramIndex>,
15}
16
17impl<'a, R, W> StepRunner<'a, R, W>
18where
19    R: Read,
20    W: Write,
21{
22    /// Create a new runner with the given inputand  output.
23    pub fn new(program: &'a Program, input: R, output: W) -> Self {
24        Self::with_memsize(program, input, output, DEFAULT_MEMSIZE)
25    }
26
27    /// Create a new runner with the given input, output and memory size.
28    pub fn with_memsize(program: &'a Program, input: R, output: W, memsize: MemorySize) -> Self {
29        let runtime = internal::Runtime::new(input, output, memsize);
30        Self {
31            program,
32            runtime,
33            index: program.first_index(),
34        }
35    }
36
37    /// Get the index of the instruction to be executed.
38    ///
39    /// If the program is finished, this returns `None`.
40    pub fn get_index(&self) -> Option<&ProgramIndex> {
41        self.index.as_ref()
42    }
43
44    /// Get the current instruction to be executed.
45    pub fn get_current_instruction(&self) -> Option<&Instruction> {
46        self.index.as_ref().map(|index| &self.program[index])
47    }
48
49    /// Get the pointer.
50    pub fn get_pointer(&self) -> isize {
51        self.runtime.get_pointer()
52    }
53
54    /// Get mutable reference of data at `addres'.
55    pub fn get_data_at_mut(&mut self, address: isize) -> Option<&mut u8> {
56        self.runtime.get_data_at_mut(address)
57    }
58
59    /// Returns `true` if the program is running.
60    pub fn is_running(&self) -> bool {
61        self.index.is_some()
62    }
63
64    /// Execute the program one step.
65    pub fn step(&mut self) -> Result<(), RuntimeError> {
66        if let Some(index) = &mut self.index {
67            let inst = &self.program[index];
68            match self.runtime.exec_one(inst)? {
69                internal::NextAction::Next => {
70                    if !self.program.step_index(index) && !index.step_out() {
71                        self.index = None;
72                    }
73                }
74                internal::NextAction::StepIn(sub) => {
75                    if !sub.is_empty() {
76                        index.step_in();
77                    }
78                }
79            }
80        }
81        Ok(())
82    }
83}