rib/interpreter/
stack.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue;
16use crate::GetLiteralValue;
17use golem_wasm_ast::analysis::analysed_type::{list, option, record, str, tuple, variant};
18use golem_wasm_ast::analysis::{
19    AnalysedType, NameOptionTypePair, NameTypePair, TypeEnum, TypeRecord, TypeResult,
20};
21use golem_wasm_rpc::{Value, ValueAndType};
22
23#[derive(Debug)]
24pub struct InterpreterStack {
25    pub stack: Vec<RibInterpreterStackValue>,
26}
27
28impl Default for InterpreterStack {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl InterpreterStack {
35    pub fn new() -> Self {
36        InterpreterStack { stack: Vec::new() }
37    }
38
39    // Initialise a record in the stack
40    pub fn create_record(&mut self, fields: Vec<NameTypePair>) {
41        self.push_val(ValueAndType::new(
42            Value::Record(
43                vec![Value::Tuple(vec![]); fields.len()], // pre-initializing with () values, to be replaced later by UpdateRecord instructions
44            ),
45            record(fields),
46        ));
47    }
48
49    pub fn pop(&mut self) -> Option<RibInterpreterStackValue> {
50        self.stack.pop()
51    }
52
53    pub fn try_pop(&mut self) -> Result<RibInterpreterStackValue, String> {
54        self.pop()
55            .ok_or("internal error: failed to pop value from the interpreter stack".to_string())
56    }
57
58    pub fn pop_sink(&mut self) -> Option<(Vec<ValueAndType>, AnalysedType)> {
59        match self.pop() {
60            Some(RibInterpreterStackValue::Sink(vec, analysed_type)) => {
61                Some((vec.clone(), analysed_type))
62            }
63            _ => None,
64        }
65    }
66
67    pub fn pop_n(&mut self, n: usize) -> Option<Vec<RibInterpreterStackValue>> {
68        let mut results = Vec::new();
69        for _ in 0..n {
70            results.push(self.stack.pop()?);
71        }
72        Some(results)
73    }
74
75    pub fn try_pop_n(&mut self, n: usize) -> Result<Vec<RibInterpreterStackValue>, String> {
76        self.pop_n(n).ok_or(format!(
77            "internal error: failed to pop {} values from the interpreter stack",
78            n
79        ))
80    }
81
82    pub fn try_pop_n_val(&mut self, n: usize) -> Result<Vec<ValueAndType>, String> {
83        let stack_values = self.try_pop_n(n)?;
84
85        stack_values
86            .iter()
87            .map(|interpreter_result| {
88                interpreter_result.get_val().ok_or(format!(
89                    "internal error: failed to convert last {} in the stack to ValueAndType",
90                    n
91                ))
92            })
93            .collect::<Result<Vec<ValueAndType>, String>>()
94    }
95
96    pub fn pop_str(&mut self) -> Option<String> {
97        self.pop_val().and_then(|v| match v {
98            ValueAndType {
99                value: Value::String(s),
100                ..
101            } => Some(s),
102            _ => None,
103        })
104    }
105
106    pub fn pop_val(&mut self) -> Option<ValueAndType> {
107        self.stack.pop().and_then(|v| v.get_val())
108    }
109
110    pub fn try_pop_val(&mut self) -> Result<ValueAndType, String> {
111        self.try_pop().and_then(|x| {
112            x.get_val().ok_or(
113                "internal error: failed to pop ValueAndType from the interpreter stack".to_string(),
114            )
115        })
116    }
117
118    pub fn try_pop_record(&mut self) -> Result<(Vec<Value>, TypeRecord), String> {
119        let value = self.try_pop_val()?;
120
121        match value {
122            ValueAndType {
123                value: Value::Record(field_values),
124                typ: AnalysedType::Record(typ),
125            } => Ok((field_values, typ)),
126            _ => Err("internal error: failed to pop a record from the interpreter".to_string()),
127        }
128    }
129
130    pub fn try_pop_bool(&mut self) -> Result<bool, String> {
131        self.try_pop_val().and_then(|val| {
132            val.get_literal().and_then(|x| x.get_bool()).ok_or(
133                "internal error: failed to pop boolean from the interpreter stack".to_string(),
134            )
135        })
136    }
137
138    pub fn push(&mut self, interpreter_result: RibInterpreterStackValue) {
139        self.stack.push(interpreter_result);
140    }
141
142    pub fn create_sink(&mut self, analysed_type: &AnalysedType) {
143        self.stack.push(RibInterpreterStackValue::Sink(
144            vec![],
145            analysed_type.clone(),
146        ))
147    }
148
149    pub fn push_val(&mut self, element: ValueAndType) {
150        self.stack.push(RibInterpreterStackValue::val(element));
151    }
152
153    pub fn push_to_sink(&mut self, value_and_type: ValueAndType) -> Result<(), String> {
154        let sink = self.pop();
155        // sink always followed by an iterator
156        let possible_iterator = self
157            .pop()
158            .ok_or("Failed to get the iterator before pushing to the sink")?;
159
160        if !possible_iterator.is_iterator() {
161            return Err("Expecting an the iterator before pushing to the sink".to_string());
162        }
163
164        match sink {
165            Some(RibInterpreterStackValue::Sink(mut list, analysed_type)) => {
166                list.push(value_and_type);
167                self.push(possible_iterator);
168                self.push(RibInterpreterStackValue::Sink(list, analysed_type));
169                Ok(())
170            }
171
172            a => Err(format!(
173                "internal error: failed to push values to sink {:?}",
174                a
175            )),
176        }
177    }
178
179    pub fn push_variant(
180        &mut self,
181        variant_name: String,
182        optional_variant_value: Option<Value>,
183        cases: Vec<NameOptionTypePair>,
184    ) -> Result<(), String> {
185        let case_idx = cases
186            .iter()
187            .position(|case| case.name == variant_name)
188            .ok_or(format!(
189                "internal Error: Failed to find the variant {} in the cases",
190                variant_name
191            ))? as u32;
192
193        let case_value = optional_variant_value.map(Box::new);
194        self.push_val(ValueAndType::new(
195            Value::Variant {
196                case_idx,
197                case_value,
198            },
199            variant(cases),
200        ));
201
202        Ok(())
203    }
204
205    pub fn push_enum(&mut self, enum_name: String, cases: Vec<String>) -> Result<(), String> {
206        let idx = cases.iter().position(|x| x == &enum_name).ok_or_else(|| {
207            format!(
208                "internal error: failed to find the enum {} in the cases",
209                enum_name
210            )
211        })? as u32;
212        self.push_val(ValueAndType::new(
213            Value::Enum(idx),
214            AnalysedType::Enum(TypeEnum {
215                cases: cases.into_iter().collect(),
216            }),
217        ));
218
219        Ok(())
220    }
221
222    pub fn push_some(&mut self, inner_element: Value, inner_type: &AnalysedType) {
223        self.push_val(ValueAndType {
224            value: Value::Option(Some(Box::new(inner_element))),
225            typ: option(inner_type.clone()),
226        });
227    }
228
229    // We allow untyped none to be in stack,
230    // Need to verify how strict we should be
231    // Example: ${match ok(1) { ok(value) => none }} should be allowed
232    pub fn push_none(&mut self, analysed_type: Option<AnalysedType>) {
233        self.push_val(ValueAndType {
234            value: Value::Option(None),
235            typ: option(analysed_type.unwrap_or(str())), // TODO: this used to be a "missing value in protobuf"
236        });
237    }
238
239    pub fn push_ok(
240        &mut self,
241        inner_element: Value,
242        ok_type: Option<&AnalysedType>,
243        err_type: Option<&AnalysedType>,
244    ) {
245        self.push_val(ValueAndType {
246            value: Value::Result(Ok(Some(Box::new(inner_element)))),
247            typ: AnalysedType::Result(TypeResult {
248                ok: ok_type.map(|x| Box::new(x.clone())),
249                err: err_type.map(|x| Box::new(x.clone())),
250            }),
251        });
252    }
253
254    pub fn push_err(
255        &mut self,
256        inner_element: Value,
257        ok_type: Option<&AnalysedType>,
258        err_type: Option<&AnalysedType>,
259    ) {
260        self.push_val(ValueAndType {
261            value: Value::Result(Err(Some(Box::new(inner_element)))),
262            typ: AnalysedType::Result(TypeResult {
263                ok: ok_type.map(|x| Box::new(x.clone())),
264                err: err_type.map(|x| Box::new(x.clone())),
265            }),
266        });
267    }
268
269    pub fn push_list(&mut self, values: Vec<Value>, list_elem_type: &AnalysedType) {
270        self.push_val(ValueAndType {
271            value: Value::List(values),
272            typ: list(list_elem_type.clone()),
273        });
274    }
275
276    pub fn push_tuple(&mut self, values: Vec<ValueAndType>) {
277        self.push_val(ValueAndType {
278            value: Value::Tuple(values.iter().map(|x| x.value.clone()).collect()),
279            typ: tuple(values.into_iter().map(|x| x.typ).collect()),
280        });
281    }
282}