rib/interpreter/
stack.rs

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