1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use super::{typed_value::TypedVal, ControlFrame};
use crate::{
engine::bytecode::{Provider, ProviderSliceStack},
Error,
};
use std::vec::{Drain, Vec};
/// An acquired branch target.
#[derive(Debug)]
pub enum AcquiredTarget<'a> {
/// The branch targets the function enclosing `block` and therefore is a `return`.
Return(&'a mut ControlFrame),
/// The branch targets a regular [`ControlFrame`].
Branch(&'a mut ControlFrame),
}
impl<'a> AcquiredTarget<'a> {
/// Returns an exclusive reference to the [`ControlFrame`] of the [`AcquiredTarget`].
pub fn control_frame(&'a mut self) -> &'a mut ControlFrame {
match self {
Self::Return(frame) => frame,
Self::Branch(frame) => frame,
}
}
}
/// The stack of control flow frames.
#[derive(Debug, Default)]
pub struct ControlStack {
/// The stack of control frames such as `block`, `loop` and `if`.
frames: Vec<ControlFrame>,
/// Special stack for parameters of `else` blocks.
///
/// # Note
///
/// This is required since both `then` and `else` branches of an
/// `if` control frame have the same input providers. However,
/// during translation of the `then` branch these inputs have
/// already been consumed. Therefore we need to duplicate them
/// here to push them back on the stack once we see the `else` branch.
else_providers: ProviderSliceStack<TypedVal>,
}
impl ControlStack {
/// Resets the [`ControlStack`] to allow for reuse.
pub fn reset(&mut self) {
self.frames.clear();
self.else_providers.reset();
}
/// Returns `true` if `relative_depth` points to the first control flow frame.
pub fn is_root(&self, relative_depth: u32) -> bool {
debug_assert!(!self.is_empty());
relative_depth as usize == self.len() - 1
}
/// Returns the current depth of the stack of the [`ControlStack`].
pub fn len(&self) -> usize {
self.frames.len()
}
/// Returns `true` if the [`ControlStack`] is empty.
pub fn is_empty(&self) -> bool {
self.frames.len() == 0
}
/// Pushes a new control flow frame to the [`ControlStack`].
pub fn push_frame<T>(&mut self, frame: T)
where
T: Into<ControlFrame>,
{
self.frames.push(frame.into())
}
/// Pops the last control flow frame from the [`ControlStack`].
///
/// # Panics
///
/// If the [`ControlStack`] is empty.
pub fn pop_frame(&mut self) -> ControlFrame {
self.frames
.pop()
.expect("tried to pop control flow frame from empty control flow stack")
}
/// Push a [`Provider`] slice for the `else` branch of an [`IfControlFrame`] to the [`ControlStack`].
///
/// [`IfControlFrame`]: super::control_frame::IfControlFrame
pub fn push_else_providers<I>(&mut self, providers: I) -> Result<(), Error>
where
I: IntoIterator<Item = Provider<TypedVal>>,
{
self.else_providers.push(providers)?;
Ok(())
}
/// Pops the top-most [`Provider`] slice of an `else` branch of an [`IfControlFrame`] to the [`ControlStack`].
///
/// [`IfControlFrame`]: super::control_frame::IfControlFrame
pub fn pop_else_providers(&mut self) -> Drain<Provider<TypedVal>> {
self.else_providers
.pop()
.expect("missing else providers for `else` branch")
}
/// Returns the last control flow frame on the control stack.
pub fn last(&self) -> &ControlFrame {
self.frames.last().expect(
"tried to exclusively peek the last control flow \
frame from an empty control flow stack",
)
}
/// Returns a shared reference to the control flow frame at the given `depth`.
///
/// A `depth` of 0 is equal to calling [`ControlStack::last`].
///
/// # Panics
///
/// If `depth` exceeds the length of the stack of control flow frames.
pub fn nth_back_mut(&mut self, depth: u32) -> &mut ControlFrame {
let len = self.len();
self.frames
.iter_mut()
.nth_back(depth as usize)
.unwrap_or_else(|| {
panic!(
"tried to peek the {depth}-th control flow frame \
but there are only {len} control flow frames",
)
})
}
/// Acquires the target [`ControlFrame`] at the given relative `depth`.
pub fn acquire_target(&mut self, depth: u32) -> AcquiredTarget {
let is_root = self.is_root(depth);
let frame = self.nth_back_mut(depth);
if is_root {
AcquiredTarget::Return(frame)
} else {
AcquiredTarget::Branch(frame)
}
}
}