Skip to main content

rib/interpreter/
stack.rs

1use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue;
2use crate::interpreter::rib_runtime_error::{
3    empty_stack, insufficient_stack_items, type_mismatch_with_value,
4};
5use crate::wit_type::{list, option, record, str, tuple, variant};
6use crate::wit_type::{
7    NameOptionTypePair, NameTypePair, TypeEnum, TypeRecord, TypeResult, WitType,
8};
9use crate::{internal_corrupted_state, GetLiteralValue, RibInterpreterResult, TypeHint};
10use crate::{Value, ValueAndType};
11
12#[derive(Debug)]
13pub struct InterpreterStack {
14    pub stack: Vec<RibInterpreterStackValue>,
15}
16
17impl Default for InterpreterStack {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23impl InterpreterStack {
24    pub fn new() -> Self {
25        InterpreterStack { stack: Vec::new() }
26    }
27
28    // Initialise a record in the stack
29    pub fn create_record(&mut self, fields: Vec<NameTypePair>) {
30        self.push_val(ValueAndType::new(
31            Value::Record(
32                vec![Value::Tuple(vec![]); fields.len()], // pre-initializing with () values, to be replaced later by UpdateRecord instructions
33            ),
34            record(fields),
35        ));
36    }
37
38    pub fn pop(&mut self) -> Option<RibInterpreterStackValue> {
39        self.stack.pop()
40    }
41
42    pub fn try_pop(&mut self) -> RibInterpreterResult<RibInterpreterStackValue> {
43        self.pop().ok_or(empty_stack())
44    }
45
46    pub fn pop_sink(&mut self) -> Option<(Vec<ValueAndType>, WitType)> {
47        while let Some(value) = self.pop() {
48            match value {
49                RibInterpreterStackValue::Sink(vec, analysed_type) => {
50                    // We found a sink, return it
51                    return Some((vec.clone(), analysed_type.clone()));
52                }
53                _ => continue, // Keep popping until we find a sink
54            }
55        }
56
57        None
58    }
59
60    pub fn pop_n(&mut self, n: usize) -> Option<Vec<RibInterpreterStackValue>> {
61        let mut results = Vec::new();
62        for _ in 0..n {
63            results.push(self.stack.pop()?);
64        }
65        Some(results)
66    }
67
68    pub fn try_pop_n(&mut self, n: usize) -> RibInterpreterResult<Vec<RibInterpreterStackValue>> {
69        self.pop_n(n).ok_or(insufficient_stack_items(n))
70    }
71
72    pub fn try_pop_n_val(&mut self, n: usize) -> RibInterpreterResult<Vec<ValueAndType>> {
73        let stack_values = self.try_pop_n(n)?;
74
75        stack_values
76            .iter()
77            .map(|interpreter_result| {
78                interpreter_result
79                    .get_val()
80                    .ok_or(internal_corrupted_state!(
81                        "failed to convert last {} in the stack to ValueAndType",
82                        n
83                    ))
84            })
85            .collect::<RibInterpreterResult<Vec<ValueAndType>>>()
86    }
87
88    pub fn pop_str(&mut self) -> Option<String> {
89        self.pop_val().and_then(|v| match v {
90            ValueAndType {
91                value: Value::String(s),
92                ..
93            } => Some(s),
94            _ => None,
95        })
96    }
97
98    pub fn pop_val(&mut self) -> Option<ValueAndType> {
99        self.stack.pop().and_then(|v| v.get_val())
100    }
101
102    pub fn try_pop_val(&mut self) -> RibInterpreterResult<ValueAndType> {
103        self.try_pop().and_then(|x| {
104            x.get_val().ok_or(internal_corrupted_state!(
105                "failed to pop ValueAndType from the interpreter stack"
106            ))
107        })
108    }
109
110    pub fn try_pop_record(&mut self) -> RibInterpreterResult<(Vec<Value>, TypeRecord)> {
111        let value = self.try_pop_val()?;
112
113        match value {
114            ValueAndType {
115                value: Value::Record(field_values),
116                typ: WitType::Record(typ),
117            } => Ok((field_values, typ)),
118            _ => Err(type_mismatch_with_value(
119                vec![TypeHint::Record(None)],
120                value.value.clone(),
121            )),
122        }
123    }
124
125    pub fn try_pop_bool(&mut self) -> RibInterpreterResult<bool> {
126        self.try_pop_val().and_then(|val| {
127            val.get_literal()
128                .and_then(|x| x.get_bool())
129                .ok_or(type_mismatch_with_value(
130                    vec![TypeHint::Boolean],
131                    val.value.clone(),
132                ))
133        })
134    }
135
136    pub fn push(&mut self, interpreter_result: RibInterpreterStackValue) {
137        self.stack.push(interpreter_result);
138    }
139
140    pub fn create_sink(&mut self, analysed_type: WitType) {
141        self.stack
142            .push(RibInterpreterStackValue::Sink(vec![], analysed_type))
143    }
144
145    pub fn push_val(&mut self, element: ValueAndType) {
146        self.stack.push(RibInterpreterStackValue::val(element));
147    }
148
149    pub fn push_to_sink(&mut self, value_and_type: ValueAndType) -> RibInterpreterResult<()> {
150        let (mut list, analysed_type) = self.pop_sink().ok_or(internal_corrupted_state!(
151            "failed to pop a sink from the interpreter stack"
152        ))?;
153
154        list.push(value_and_type);
155        self.push(RibInterpreterStackValue::Sink(list, analysed_type));
156        Ok(())
157    }
158
159    pub fn push_variant(
160        &mut self,
161        variant_name: String,
162        optional_variant_value: Option<Value>,
163        cases: Vec<NameOptionTypePair>,
164    ) -> RibInterpreterResult<()> {
165        let case_idx = cases
166            .iter()
167            .position(|case| case.name == variant_name)
168            .ok_or(internal_corrupted_state!(
169                "failed to find the variant {}",
170                variant_name
171            ))? as u32;
172
173        let case_value = optional_variant_value.map(Box::new);
174        self.push_val(ValueAndType::new(
175            Value::Variant {
176                case_idx,
177                case_value,
178            },
179            variant(cases),
180        ));
181
182        Ok(())
183    }
184
185    pub fn push_enum(&mut self, enum_name: String, cases: Vec<String>) -> RibInterpreterResult<()> {
186        let idx = cases.iter().position(|x| x == &enum_name).ok_or_else(|| {
187            internal_corrupted_state!("failed to find the enum {} in the cases", enum_name)
188        })? as u32;
189        self.push_val(ValueAndType::new(
190            Value::Enum(idx),
191            WitType::Enum(TypeEnum {
192                cases: cases.into_iter().collect(),
193                name: None,
194                owner: None,
195            }),
196        ));
197
198        Ok(())
199    }
200
201    pub fn push_some(&mut self, inner_element: Value, inner_type: &WitType) {
202        self.push_val(ValueAndType {
203            value: Value::Option(Some(Box::new(inner_element))),
204            typ: option(inner_type.clone()),
205        });
206    }
207
208    // We allow untyped none to be in stack,
209    // Need to verify how strict we should be
210    // Example: ${match ok(1) { ok(value) => none }} should be allowed
211    pub fn push_none(&mut self, analysed_type: Option<WitType>) {
212        self.push_val(ValueAndType {
213            value: Value::Option(None),
214            typ: option(analysed_type.unwrap_or(str())), // TODO: this used to be a "missing value in protobuf"
215        });
216    }
217
218    pub fn push_ok(
219        &mut self,
220        inner_element: Value,
221        ok_type: Option<&WitType>,
222        err_type: Option<&WitType>,
223    ) {
224        self.push_val(ValueAndType {
225            value: Value::Result(Ok(Some(Box::new(inner_element)))),
226            typ: WitType::Result(TypeResult {
227                ok: ok_type.map(|x| Box::new(x.clone())),
228                err: err_type.map(|x| Box::new(x.clone())),
229                name: None,
230                owner: None,
231            }),
232        });
233    }
234
235    pub fn push_err(
236        &mut self,
237        inner_element: Value,
238        ok_type: Option<&WitType>,
239        err_type: Option<&WitType>,
240    ) {
241        self.push_val(ValueAndType {
242            value: Value::Result(Err(Some(Box::new(inner_element)))),
243            typ: WitType::Result(TypeResult {
244                ok: ok_type.map(|x| Box::new(x.clone())),
245                err: err_type.map(|x| Box::new(x.clone())),
246                name: None,
247                owner: None,
248            }),
249        });
250    }
251
252    pub fn push_list(&mut self, values: Vec<Value>, list_elem_type: &WitType) {
253        self.push_val(ValueAndType {
254            value: Value::List(values),
255            typ: list(list_elem_type.clone()),
256        });
257    }
258
259    pub fn push_tuple(&mut self, values: Vec<ValueAndType>) {
260        self.push_val(ValueAndType {
261            value: Value::Tuple(values.iter().map(|x| x.value.clone()).collect()),
262            typ: tuple(values.into_iter().map(|x| x.typ).collect()),
263        });
264    }
265}