]> git.lizzy.rs Git - rust.git/blob - src/interpreter/iterator.rs
stepwise interpretation
[rust.git] / src / interpreter / iterator.rs
1 use super::{
2     FnEvalContext,
3     CachedMir,
4     TerminatorTarget,
5 };
6 use error::EvalResult;
7 use rustc::mir::repr as mir;
8
9 pub enum Event<'a, 'tcx: 'a> {
10     Assignment(&'a mir::Statement<'tcx>),
11     Terminator(&'a mir::Terminator<'tcx>),
12     Done,
13 }
14
15 pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
16     fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
17     block: mir::BasicBlock,
18     stmt: usize,
19     mir: CachedMir<'mir, 'tcx>,
20     process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
21 }
22
23 impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
24     pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
25         Stepper {
26             block: fncx.frame().next_block,
27             mir: fncx.mir(),
28             fncx: fncx,
29             stmt: 0,
30             process: Self::dummy,
31         }
32     }
33     fn dummy(&mut self) -> EvalResult<()> { Ok(()) }
34     fn statement(&mut self) -> EvalResult<()> {
35         let block_data = self.mir.basic_block_data(self.block);
36         let stmt = &block_data.statements[self.stmt];
37         let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
38         let result = self.fncx.eval_assignment(lvalue, rvalue);
39         self.fncx.maybe_report(stmt.span, result)?;
40         self.stmt += 1;
41         Ok(())
42     }
43     fn terminator(&mut self) -> EvalResult<()> {
44         self.stmt = 0;
45         let term = {
46             let block_data = self.mir.basic_block_data(self.block);
47             let terminator = block_data.terminator();
48             let result = self.fncx.eval_terminator(terminator);
49             self.fncx.maybe_report(terminator.span, result)?
50         };
51         match term {
52             TerminatorTarget::Block(block) => {
53                 self.block = block;
54             },
55             TerminatorTarget::Return => {
56                 self.fncx.pop_stack_frame();
57                 self.fncx.name_stack.pop();
58                 if !self.fncx.stack.is_empty() {
59                     self.block = self.fncx.frame().next_block;
60                     self.mir = self.fncx.mir();
61                 }
62             },
63             TerminatorTarget::Call => {
64                 self.block = self.fncx.frame().next_block;
65                 self.mir = self.fncx.mir();
66             },
67         }
68         Ok(())
69     }
70     pub fn step<'step>(&'step mut self) -> EvalResult<Event<'step, 'tcx>> {
71         (self.process)(self)?;
72
73         if self.fncx.stack.is_empty() {
74             // fuse the iterator
75             self.process = Self::dummy;
76             return Ok(Event::Done);
77         }
78
79         let basic_block = self.mir.basic_block_data(self.block);
80
81         if let Some(stmt) = basic_block.statements.get(self.stmt) {
82             self.process = Self::statement;
83             return Ok(Event::Assignment(&stmt));
84         }
85
86         self.process = Self::terminator;
87         Ok(Event::Terminator(basic_block.terminator()))
88     }
89     pub fn block(&self) -> mir::BasicBlock {
90         self.block
91     }
92 }