rib/interpreter/
rib_interpreter.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::env::InterpreterEnv;
16use crate::interpreter::instruction_cursor::RibByteCodeCursor;
17use crate::interpreter::stack::InterpreterStack;
18use crate::{RibByteCode, RibFunctionInvoke, RibIR, RibInput, RibResult};
19use std::sync::Arc;
20
21use super::interpreter_stack_value::RibInterpreterStackValue;
22
23pub struct Interpreter {
24    pub input: RibInput,
25    pub invoke: Arc<dyn RibFunctionInvoke + Sync + Send>,
26    pub custom_stack: Option<InterpreterStack>,
27    pub custom_env: Option<InterpreterEnv>,
28}
29
30impl Default for Interpreter {
31    fn default() -> Self {
32        Interpreter {
33            input: RibInput::default(),
34            invoke: Arc::new(internal::NoopRibFunctionInvoke),
35            custom_stack: None,
36            custom_env: None,
37        }
38    }
39}
40
41impl Interpreter {
42    pub fn new(
43        input: &RibInput,
44        invoke: Arc<dyn RibFunctionInvoke + Sync + Send>,
45        custom_stack: Option<InterpreterStack>,
46        custom_env: Option<InterpreterEnv>,
47    ) -> Self {
48        Interpreter {
49            input: input.clone(),
50            invoke,
51            custom_stack,
52            custom_env,
53        }
54    }
55
56    // Interpreter that's not expected to call a side-effecting function call.
57    // All it needs is environment with the required variables to evaluate the Rib script
58    pub fn pure(
59        input: &RibInput,
60        custom_stack: Option<InterpreterStack>,
61        custom_env: Option<InterpreterEnv>,
62    ) -> Self {
63        Interpreter {
64            input: input.clone(),
65            invoke: Arc::new(internal::NoopRibFunctionInvoke),
66            custom_stack,
67            custom_env,
68        }
69    }
70
71    // Override rib input helps with incremental interpretation
72    // where a rib script is now trying to access a specific input
73    // such that the compiler already knows the required global variable and its types,
74    // to later override the interpreter with this input. The previous inputs will be completely
75    // discard as they are either loaded in as variables, or if they are accessed again, the inputs
76    // will be or can be overriden back
77    pub fn override_rib_input(&mut self, rib_input: RibInput) {
78        self.input = rib_input;
79    }
80
81    pub async fn run(&mut self, instructions0: RibByteCode) -> Result<RibResult, String> {
82        let mut byte_code_cursor = RibByteCodeCursor::from_rib_byte_code(instructions0);
83        let stack = match &mut self.custom_stack {
84            Some(custom) => custom,
85            None => &mut InterpreterStack::default(),
86        };
87
88        let interpreter_env = match &mut self.custom_env {
89            Some(custom) => custom,
90            None => &mut InterpreterEnv::from(&self.input, &self.invoke),
91        };
92
93        while let Some(instruction) = byte_code_cursor.get_instruction() {
94            match instruction {
95                RibIR::PushLit(val) => {
96                    stack.push_val(val);
97                }
98
99                RibIR::PushFlag(val) => {
100                    stack.push_val(val);
101                }
102
103                RibIR::CreateAndPushRecord(analysed_type) => {
104                    internal::run_create_record_instruction(analysed_type, stack)?;
105                }
106
107                RibIR::UpdateRecord(field_name) => {
108                    internal::run_update_record_instruction(field_name, stack)?;
109                }
110
111                RibIR::PushList(analysed_type, arg_size) => {
112                    internal::run_push_list_instruction(arg_size, analysed_type, stack)?;
113                }
114
115                RibIR::EqualTo => {
116                    internal::run_compare_instruction(stack, |left, right| left == right)?;
117                }
118
119                RibIR::GreaterThan => {
120                    internal::run_compare_instruction(stack, |left, right| left > right)?;
121                }
122
123                RibIR::LessThan => {
124                    internal::run_compare_instruction(stack, |left, right| left < right)?;
125                }
126
127                RibIR::GreaterThanOrEqualTo => {
128                    internal::run_compare_instruction(stack, |left, right| left >= right)?;
129                }
130
131                RibIR::LessThanOrEqualTo => {
132                    internal::run_compare_instruction(stack, |left, right| left <= right)?;
133                }
134                RibIR::Plus(analysed_type) => {
135                    internal::run_math_instruction(
136                        stack,
137                        |left, right| left + right,
138                        &analysed_type,
139                    )?;
140                }
141                RibIR::Minus(analysed_type) => {
142                    internal::run_math_instruction(
143                        stack,
144                        |left, right| left - right,
145                        &analysed_type,
146                    )?;
147                }
148                RibIR::Divide(analysed_type) => {
149                    internal::run_math_instruction(
150                        stack,
151                        |left, right| left / right,
152                        &analysed_type,
153                    )?;
154                }
155                RibIR::Multiply(analysed_type) => {
156                    internal::run_math_instruction(
157                        stack,
158                        |left, right| left * right,
159                        &analysed_type,
160                    )?;
161                }
162
163                RibIR::AssignVar(variable_id) => {
164                    internal::run_assign_var_instruction(variable_id, stack, interpreter_env)?;
165                }
166
167                RibIR::LoadVar(variable_id) => {
168                    internal::run_load_var_instruction(variable_id, stack, interpreter_env)?;
169                }
170
171                RibIR::IsEmpty => {
172                    internal::run_is_empty_instruction(stack)?;
173                }
174
175                RibIR::JumpIfFalse(instruction_id) => {
176                    internal::run_jump_if_false_instruction(
177                        instruction_id,
178                        &mut byte_code_cursor,
179                        stack,
180                    )?;
181                }
182
183                RibIR::SelectField(field_name) => {
184                    internal::run_select_field_instruction(field_name, stack)?;
185                }
186
187                RibIR::SelectIndex(index) => {
188                    internal::run_select_index_instruction(stack, index)?;
189                }
190
191                RibIR::SelectIndexV1 => {
192                    internal::run_select_index_v1_instruction(stack)?;
193                }
194
195                RibIR::CreateFunctionName(site, function_type) => {
196                    internal::run_create_function_name_instruction(site, function_type, stack)?;
197                }
198
199                RibIR::InvokeFunction(worker_type, arg_size, _) => {
200                    internal::run_call_instruction(arg_size, worker_type, stack, interpreter_env)
201                        .await?;
202                }
203
204                RibIR::PushVariant(variant_name, analysed_type) => {
205                    internal::run_variant_construction_instruction(
206                        variant_name,
207                        analysed_type,
208                        stack,
209                    )
210                    .await?;
211                }
212
213                RibIR::PushEnum(enum_name, analysed_type) => {
214                    internal::run_push_enum_instruction(stack, enum_name, analysed_type)?;
215                }
216
217                RibIR::Throw(message) => {
218                    return Err(message);
219                }
220
221                RibIR::GetTag => {
222                    internal::run_get_tag_instruction(stack)?;
223                }
224
225                RibIR::Deconstruct => {
226                    internal::run_deconstruct_instruction(stack)?;
227                }
228
229                RibIR::Jump(instruction_id) => {
230                    byte_code_cursor.move_to(&instruction_id).ok_or_else(|| {
231                        format!(
232                            "internal error. Failed to move to label {}",
233                            instruction_id.index
234                        )
235                    })?;
236                }
237
238                RibIR::PushSome(analysed_type) => {
239                    internal::run_create_some_instruction(stack, analysed_type)?;
240                }
241                RibIR::PushNone(analysed_type) => {
242                    internal::run_create_none_instruction(stack, analysed_type)?;
243                }
244                RibIR::PushOkResult(analysed_type) => {
245                    internal::run_create_ok_instruction(stack, analysed_type)?;
246                }
247                RibIR::PushErrResult(analysed_type) => {
248                    internal::run_create_err_instruction(stack, analysed_type)?;
249                }
250                RibIR::Concat(arg_size) => {
251                    internal::run_concat_instruction(stack, arg_size)?;
252                }
253                RibIR::PushTuple(analysed_type, arg_size) => {
254                    internal::run_push_tuple_instruction(arg_size, analysed_type, stack)?;
255                }
256                RibIR::Negate => {
257                    internal::run_negate_instruction(stack)?;
258                }
259
260                RibIR::Label(_) => {}
261
262                RibIR::And => {
263                    internal::run_and_instruction(stack)?;
264                }
265
266                RibIR::Or => {
267                    internal::run_or_instruction(stack)?;
268                }
269                RibIR::ToIterator => {
270                    internal::run_to_iterator(stack)?;
271                }
272                RibIR::CreateSink(analysed_type) => {
273                    internal::run_create_sink_instruction(stack, &analysed_type)?
274                }
275                RibIR::AdvanceIterator => {
276                    internal::run_advance_iterator_instruction(stack)?;
277                }
278                RibIR::PushToSink => {
279                    internal::run_push_to_sink_instruction(stack)?;
280                }
281
282                RibIR::SinkToList => {
283                    internal::run_sink_to_list_instruction(stack)?;
284                }
285
286                RibIR::Length => {
287                    internal::run_length_instruction(stack)?;
288                }
289            }
290        }
291
292        let stack_value = stack
293            .pop()
294            .unwrap_or_else(|| RibInterpreterStackValue::Unit);
295
296        let rib_result = RibResult::from_rib_interpreter_stack_value(&stack_value)
297            .ok_or_else(|| "Failed to obtain a valid result from rib execution".to_string())?;
298
299        Ok(rib_result)
300    }
301}
302
303mod internal {
304    use crate::interpreter::env::{EnvironmentKey, InterpreterEnv};
305    use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue;
306    use crate::interpreter::literal::LiteralValue;
307    use crate::interpreter::stack::InterpreterStack;
308    use crate::{
309        CoercedNumericValue, EvaluatedFnArgs, EvaluatedFqFn, EvaluatedWorkerName,
310        FunctionReferenceType, InstructionId, ParsedFunctionName, ParsedFunctionReference,
311        ParsedFunctionSite, RibFunctionInvoke, VariableId, WorkerNamePresence,
312    };
313    use golem_wasm_ast::analysis::AnalysedType;
314    use golem_wasm_ast::analysis::TypeResult;
315    use golem_wasm_rpc::{print_value_and_type, IntoValueAndType, Value, ValueAndType};
316
317    use crate::interpreter::instruction_cursor::RibByteCodeCursor;
318    use async_trait::async_trait;
319    use golem_wasm_ast::analysis::analysed_type::{tuple, u64};
320    use std::ops::Deref;
321
322    pub(crate) struct NoopRibFunctionInvoke;
323
324    #[async_trait]
325    impl RibFunctionInvoke for NoopRibFunctionInvoke {
326        async fn invoke(
327            &self,
328            _worker_name: Option<EvaluatedWorkerName>,
329            _function_name: EvaluatedFqFn,
330            _args: EvaluatedFnArgs,
331        ) -> Result<ValueAndType, String> {
332            Ok(ValueAndType {
333                value: Value::Tuple(vec![]),
334                typ: tuple(vec![]),
335            })
336        }
337    }
338
339    pub(crate) fn run_is_empty_instruction(
340        interpreter_stack: &mut InterpreterStack,
341    ) -> Result<(), String> {
342        let rib_result = interpreter_stack.pop().ok_or_else(|| {
343            "internal Error: Failed to get a value from the stack to do check is_empty".to_string()
344        })?;
345
346        let bool_opt = match rib_result {
347            RibInterpreterStackValue::Val(ValueAndType {
348                value: Value::List(items),
349                ..
350            }) => Some(items.is_empty()),
351            RibInterpreterStackValue::Iterator(iter) => {
352                let mut peekable_iter = iter.peekable();
353                let result = peekable_iter.peek().is_some();
354                interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(peekable_iter)));
355                Some(result)
356            }
357            RibInterpreterStackValue::Sink(values, analysed_type) => {
358                let possible_iterator = interpreter_stack.pop().ok_or_else(|| {
359                    "internal error: Expecting an iterator to check is empty".to_string()
360                })?;
361
362                match possible_iterator {
363                    RibInterpreterStackValue::Iterator(iter) => {
364                        let mut peekable_iter = iter.peekable();
365                        let result = peekable_iter.peek().is_some();
366                        interpreter_stack
367                            .push(RibInterpreterStackValue::Iterator(Box::new(peekable_iter)));
368                        interpreter_stack
369                            .push(RibInterpreterStackValue::Sink(values, analysed_type));
370                        Some(result)
371                    }
372
373                    _ => None,
374                }
375            }
376            RibInterpreterStackValue::Val(_) => None,
377            RibInterpreterStackValue::Unit => None,
378        };
379
380        let bool = bool_opt.ok_or("internal error: Failed to run instruction is_empty")?;
381        interpreter_stack.push_val(bool.into_value_and_type());
382        Ok(())
383    }
384
385    pub(crate) fn run_jump_if_false_instruction(
386        instruction_id: InstructionId,
387        instruction_stack: &mut RibByteCodeCursor,
388        interpreter_stack: &mut InterpreterStack,
389    ) -> Result<(), String> {
390        let predicate = interpreter_stack.try_pop_bool()?;
391
392        // Jump if predicate is false
393        if !predicate {
394            instruction_stack.move_to(&instruction_id).ok_or_else(|| {
395                format!(
396                    "internal error: Failed to move to the instruction at {}",
397                    instruction_id.index
398                )
399            })?;
400        }
401
402        Ok(())
403    }
404
405    pub(crate) fn run_to_iterator(interpreter_stack: &mut InterpreterStack) -> Result<(), String> {
406        let popped_up = interpreter_stack
407            .pop()
408            .ok_or_else(|| "internal error: failed to get a value from the stack".to_string())?;
409
410        let value_and_type = popped_up
411            .get_val()
412            .ok_or_else(|| "internal error: failed to get a value from the stack".to_string())?;
413
414        match (value_and_type.value, value_and_type.typ) {
415            (Value::List(items), AnalysedType::List(item_type)) => {
416                let items = items
417                    .into_iter()
418                    .map(|item| ValueAndType::new(item, (*item_type.inner).clone()))
419                    .collect::<Vec<_>>();
420
421                interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(
422                    items.into_iter(),
423                )));
424
425                Ok(())
426            }
427            (Value::Record(fields), AnalysedType::Record(record_type)) => {
428                let mut from: Option<usize> = None;
429                let mut to: Option<usize> = None;
430                let mut inclusive = false;
431
432                let value_and_names = fields.into_iter().zip(record_type.fields);
433
434                for (value, name_and_type) in value_and_names {
435                    match name_and_type.name.as_str() {
436                        "from" => {
437                            from =
438                                Some(to_num(&value).ok_or_else(|| {
439                                    format!("cannot cast {:?} to a number", value)
440                                })?)
441                        }
442                        "to" => {
443                            to =
444                                Some(to_num(&value).ok_or_else(|| {
445                                    format!("cannot cast {:?} to a number", value)
446                                })?)
447                        }
448                        "inclusive" => {
449                            inclusive = match value {
450                                Value::Bool(b) => b,
451                                _ => return Err("inclusive field should be a boolean".to_string()),
452                            }
453                        }
454                        _ => return Err(format!("Invalid field name {}", name_and_type.name)),
455                    }
456                }
457
458                match (from, to) {
459                    (Some(from), Some(to)) => {
460                        if inclusive {
461                            interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(
462                                (from..=to)
463                                    .map(|i| ValueAndType::new(Value::U64(i as u64), u64())),
464                            )));
465                        } else {
466                            interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(
467                                (from..to)
468                                    .map(|i| ValueAndType::new(Value::U64(i as u64), u64())),
469                            )));
470                        }
471                    }
472
473                    (None, Some(to)) => {
474                        if inclusive {
475                            interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(
476                                (0..=to)
477                                    .map(|i| ValueAndType::new(Value::U64(i as u64), u64())),
478                            )));
479                        } else {
480                            interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(
481                                (0..to)
482                                    .map(|i| ValueAndType::new(Value::U64(i as u64), u64())),
483                            )));
484                        }
485                    }
486
487                    // avoiding panicking with stack overflow for rib like the following
488                    // for i in 0.. {
489                    //   yield i
490                    // }
491                    (Some(_), None) => {
492                        return Err("an infinite range is being iterated. make sure range is finite to avoid infinite computation".to_string())
493                    }
494
495                    (None, None) => {
496                        interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new({
497                            let range = 0..;
498                            range
499                                .into_iter()
500                                .map(|i| ValueAndType::new(Value::U64(i as u64), u64()))
501                        })));
502                    }
503                };
504
505                Ok(())
506            }
507
508            _ => Err("internal error: failed to convert to an iterator".to_string()),
509        }
510    }
511
512    fn to_num(value: &Value) -> Option<usize> {
513        match value {
514            Value::U64(u64) => Some(*u64 as usize),
515            Value::Bool(_) => None,
516            Value::U8(u8) => Some(*u8 as usize),
517            Value::U16(u16) => Some(*u16 as usize),
518            Value::U32(u32) => Some(*u32 as usize),
519            Value::S8(s8) => Some(*s8 as usize),
520            Value::S16(s16) => Some(*s16 as usize),
521            Value::S32(s32) => Some(*s32 as usize),
522            Value::S64(s64) => Some(*s64 as usize),
523            Value::F32(f32) => Some(*f32 as usize),
524            Value::F64(f64) => Some(*f64 as usize),
525            _ => None,
526        }
527    }
528
529    pub(crate) fn run_create_sink_instruction(
530        interpreter_stack: &mut InterpreterStack,
531        analysed_type: &AnalysedType,
532    ) -> Result<(), String> {
533        let analysed_type = match analysed_type {
534            AnalysedType::List(type_list) => type_list.clone().inner,
535            _ => return Err("Expecting a list type to create sink".to_string()),
536        };
537        interpreter_stack.create_sink(analysed_type.deref());
538        Ok(())
539    }
540
541    pub(crate) fn run_advance_iterator_instruction(
542        interpreter_stack: &mut InterpreterStack,
543    ) -> Result<(), String> {
544        let mut rib_result = interpreter_stack
545            .pop()
546            .ok_or_else(|| "internal error: failed to advance the iterator".to_string())?;
547
548        match &mut rib_result {
549            RibInterpreterStackValue::Sink(_, _) => {
550                let mut existing_iterator = interpreter_stack
551                    .pop()
552                    .ok_or("internal error: failed to get an iterator")?;
553
554                match &mut existing_iterator {
555                    RibInterpreterStackValue::Iterator(iter) => {
556                        if let Some(value_and_type) = iter.next() {
557                            interpreter_stack.push(existing_iterator);
558                            interpreter_stack.push(rib_result);
559                            interpreter_stack.push(RibInterpreterStackValue::Val(value_and_type));
560                            Ok(())
561                        } else {
562                            Err("no more items found in the iterator".to_string())
563                        }
564                    }
565
566                    _ => Err(
567                        "internal error: A sink cannot exist without a corresponding iterator"
568                            .to_string(),
569                    ),
570                }
571            }
572
573            RibInterpreterStackValue::Iterator(iter) => {
574                if let Some(value_and_type) = iter.next() {
575                    interpreter_stack.push(rib_result);
576                    interpreter_stack.push(RibInterpreterStackValue::Val(value_and_type));
577                    Ok(())
578                } else {
579                    Err("no more items found in the iterator".to_string())
580                }
581            }
582            _ => Err("internal Error: expected an iterator".to_string()),
583        }
584    }
585
586    pub(crate) fn run_push_to_sink_instruction(
587        interpreter_stack: &mut InterpreterStack,
588    ) -> Result<(), String> {
589        let last_value = interpreter_stack.pop_val();
590        match last_value {
591            Some(val) => {
592                interpreter_stack.push_to_sink(val)?;
593
594                Ok(())
595            }
596            _ => Err("Failed to push values to sink".to_string()),
597        }
598    }
599
600    pub(crate) fn run_sink_to_list_instruction(
601        interpreter_stack: &mut InterpreterStack,
602    ) -> Result<(), String> {
603        let (result, analysed_type) = interpreter_stack
604            .pop_sink()
605            .ok_or("Failed to retrieve items from sink")?;
606
607        interpreter_stack.push_list(
608            result.into_iter().map(|vnt| vnt.value).collect(),
609            &analysed_type,
610        );
611
612        Ok(())
613    }
614
615    pub(crate) fn run_length_instruction(
616        interpreter_stack: &mut InterpreterStack,
617    ) -> Result<(), String> {
618        let rib_result = interpreter_stack
619            .pop()
620            .ok_or("internal error: failed to get a value from the stack")?;
621
622        let length = match rib_result {
623            RibInterpreterStackValue::Val(ValueAndType {
624                value: Value::List(items),
625                ..
626            }) => items.len(),
627            RibInterpreterStackValue::Iterator(iter) => iter.count(),
628            _ => return Err("internal error: failed to get the length of the value".to_string()),
629        };
630
631        interpreter_stack.push_val(ValueAndType::new(Value::U64(length as u64), u64()));
632        Ok(())
633    }
634
635    pub(crate) fn run_assign_var_instruction(
636        variable_id: VariableId,
637        interpreter_stack: &mut InterpreterStack,
638        interpreter_env: &mut InterpreterEnv,
639    ) -> Result<(), String> {
640        let value = interpreter_stack.pop().ok_or_else(|| {
641            "Expected a value on the stack before assigning a variable".to_string()
642        })?;
643        let env_key = EnvironmentKey::from(variable_id);
644
645        interpreter_env.insert(env_key, value);
646        Ok(())
647    }
648
649    pub(crate) fn run_load_var_instruction(
650        variable_id: VariableId,
651        interpreter_stack: &mut InterpreterStack,
652        interpreter_env: &mut InterpreterEnv,
653    ) -> Result<(), String> {
654        let env_key = EnvironmentKey::from(variable_id.clone());
655        let value = interpreter_env.lookup(&env_key).ok_or_else(|| {
656            format!(
657                "`{}` not found. If this is a global input, pass it to the rib interpreter",
658                variable_id
659            )
660        })?;
661
662        match value {
663            RibInterpreterStackValue::Unit => {
664                interpreter_stack.push(RibInterpreterStackValue::Unit);
665            }
666            RibInterpreterStackValue::Val(val) => interpreter_stack.push_val(val.clone()),
667            RibInterpreterStackValue::Iterator(_) => {
668                return Err("Unable to assign an iterator to a variable".to_string())
669            }
670            RibInterpreterStackValue::Sink(_, _) => {
671                return Err("Unable to assign a sink to a variable".to_string())
672            }
673        }
674
675        Ok(())
676    }
677
678    pub(crate) fn run_create_record_instruction(
679        analysed_type: AnalysedType,
680        interpreter_stack: &mut InterpreterStack,
681    ) -> Result<(), String> {
682        let name_type_pair = match analysed_type {
683            AnalysedType::Record(type_record) => type_record.fields,
684            _ => {
685                return Err(format!(
686                    "internal error: expected a record type to create a record, but obtained {:?}",
687                    analysed_type
688                ))
689            }
690        };
691
692        interpreter_stack.create_record(name_type_pair);
693        Ok(())
694    }
695
696    pub(crate) fn run_update_record_instruction(
697        field_name: String,
698        interpreter_stack: &mut InterpreterStack,
699    ) -> Result<(), String> {
700        let (current_record_fields, record_type) = interpreter_stack.try_pop_record()?;
701
702        let idx = record_type
703            .fields
704            .iter()
705            .position(|pair| pair.name == field_name)
706            .ok_or_else(|| {
707                format!(
708                    "Invalid field name {field_name}, should be one of {}",
709                    record_type
710                        .fields
711                        .iter()
712                        .map(|pair| pair.name.clone())
713                        .collect::<Vec<_>>()
714                        .join(", ")
715                )
716            })?;
717        let value = interpreter_stack.try_pop_val()?;
718
719        let mut fields = current_record_fields;
720        fields[idx] = value.value;
721
722        interpreter_stack.push_val(ValueAndType {
723            value: Value::Record(fields),
724            typ: AnalysedType::Record(record_type),
725        });
726        Ok(())
727    }
728
729    pub(crate) fn run_push_list_instruction(
730        list_size: usize,
731        analysed_type: AnalysedType,
732        interpreter_stack: &mut InterpreterStack,
733    ) -> Result<(), String> {
734        match analysed_type {
735            AnalysedType::List(inner_type) => {
736                let items =
737                    interpreter_stack.try_pop_n_val(list_size)?;
738
739
740                interpreter_stack.push_list(items.into_iter().map(|vnt| vnt.value).collect(), inner_type.inner.deref());
741
742                Ok(())
743            }
744
745            _ => Err(format!("internal error: failed to create tuple due to mismatch in types. expected: list, actual: {:?}", analysed_type)),
746        }
747    }
748
749    pub(crate) fn run_push_tuple_instruction(
750        list_size: usize,
751        analysed_type: AnalysedType,
752        interpreter_stack: &mut InterpreterStack,
753    ) -> Result<(), String> {
754        match analysed_type {
755            AnalysedType::Tuple(_inner_type) => {
756                let items =
757                    interpreter_stack.try_pop_n_val(list_size)?;
758                interpreter_stack.push_tuple(items);
759                Ok(())
760            }
761
762            _ => Err(format!("internal error: failed to create tuple due to mismatch in types. expected: tuple, actual: {:?}", analysed_type)),
763        }
764    }
765
766    pub(crate) fn run_negate_instruction(
767        interpreter_stack: &mut InterpreterStack,
768    ) -> Result<(), String> {
769        let bool = interpreter_stack.try_pop_bool()?;
770        let negated = !bool;
771
772        interpreter_stack.push_val(negated.into_value_and_type());
773        Ok(())
774    }
775
776    pub(crate) fn run_and_instruction(
777        interpreter_stack: &mut InterpreterStack,
778    ) -> Result<(), String> {
779        let left = interpreter_stack.try_pop()?;
780        let right = interpreter_stack.try_pop()?;
781
782        let result = left.compare(&right, |a, b| match (a.get_bool(), b.get_bool()) {
783            (Some(a), Some(b)) => a && b,
784            _ => false,
785        })?;
786
787        interpreter_stack.push(result);
788
789        Ok(())
790    }
791
792    pub(crate) fn run_or_instruction(
793        interpreter_stack: &mut InterpreterStack,
794    ) -> Result<(), String> {
795        let left = interpreter_stack.try_pop()?;
796        let right = interpreter_stack.try_pop()?;
797
798        let result = left.compare(&right, |a, b| match (a.get_bool(), b.get_bool()) {
799            (Some(a), Some(b)) => a || b,
800            _ => false,
801        })?;
802
803        interpreter_stack.push(result);
804
805        Ok(())
806    }
807
808    pub(crate) fn run_math_instruction(
809        interpreter_stack: &mut InterpreterStack,
810        compare_fn: fn(CoercedNumericValue, CoercedNumericValue) -> CoercedNumericValue,
811        target_numerical_type: &AnalysedType,
812    ) -> Result<(), String> {
813        let left = interpreter_stack.try_pop()?;
814        let right = interpreter_stack.try_pop()?;
815
816        let result = left.evaluate_math_op(&right, compare_fn)?;
817        let numerical_type = result.cast_to(target_numerical_type).ok_or_else(|| {
818            format!(
819                "failed to cast number {} to {:?}",
820                result, target_numerical_type
821            )
822        })?;
823
824        interpreter_stack.push_val(numerical_type);
825
826        Ok(())
827    }
828
829    pub(crate) fn run_compare_instruction(
830        interpreter_stack: &mut InterpreterStack,
831        compare_fn: fn(LiteralValue, LiteralValue) -> bool,
832    ) -> Result<(), String> {
833        let left = interpreter_stack.try_pop()?;
834        let right = interpreter_stack.try_pop()?;
835
836        let result = left.compare(&right, compare_fn)?;
837
838        interpreter_stack.push(result);
839
840        Ok(())
841    }
842
843    // Kept for backward compatibility with byte code
844    pub(crate) fn run_select_field_instruction(
845        field_name: String,
846        interpreter_stack: &mut InterpreterStack,
847    ) -> Result<(), String> {
848        let record = interpreter_stack.try_pop()?;
849
850        match record {
851            RibInterpreterStackValue::Val(ValueAndType {
852                value: Value::Record(field_values),
853                typ: AnalysedType::Record(typ),
854            }) => {
855                let field = field_values
856                    .into_iter()
857                    .zip(typ.fields)
858                    .find(|(_value, field)| field.name == field_name)
859                    .ok_or_else(|| format!("Field {} not found in the record", field_name))?;
860
861                let value = field.0;
862                interpreter_stack.push_val(ValueAndType::new(value, field.1.typ));
863                Ok(())
864            }
865            result => {
866                let stack_value_as_string = String::try_from(result)?;
867
868                Err(format!(
869                    "Unable to select field `{}` as the input `{}` is not a `record` type",
870                    field_name, stack_value_as_string
871                ))
872            }
873        }
874    }
875
876    pub(crate) fn run_select_index_v1_instruction(
877        interpreter_stack: &mut InterpreterStack,
878    ) -> Result<(), String> {
879        let stack_list_value = interpreter_stack
880            .pop()
881            .ok_or_else(|| "internal error: failed to get value from the stack".to_string())?;
882
883        let index_value = interpreter_stack
884            .pop()
885            .ok_or("internal error: failed to get the index expression from the stack")?;
886
887        match stack_list_value {
888            RibInterpreterStackValue::Val(ValueAndType {
889                value: Value::List(items),
890                typ: AnalysedType::List(typ),
891            }) => match index_value.get_literal().and_then(|v| v.get_number()) {
892                Some(CoercedNumericValue::PosInt(index)) => {
893                    let value = items
894                        .get(index as usize)
895                        .ok_or_else(|| format!(
896                            "index {} is out of bound in the list of length {}",
897                            index,
898                            items.len()
899                        ))?
900                        .clone();
901
902                    interpreter_stack.push_val(ValueAndType::new(value, (*typ.inner).clone()));
903                    Ok(())
904                }
905                _ => Err("internal error: range selection not supported at byte code level. missing desugar phase".to_string()),
906            },
907            RibInterpreterStackValue::Val(ValueAndType {
908                value: Value::Tuple(items),
909                typ: AnalysedType::Tuple(typ),
910            }) => match index_value.get_literal().and_then(|v| v.get_number()) {
911                Some(CoercedNumericValue::PosInt(index)) => {
912                    let value = items
913                        .get(index as usize)
914                        .ok_or_else(|| format!(
915                            "index {} is out of bound in a tuple of length {}",
916                            index,
917                            items.len()
918                        ))?
919                        .clone();
920
921                    let item_type = typ
922                        .items
923                        .get(index as usize)
924                        .ok_or_else(|| format!(
925                            "internal error: type not found in the tuple at index {}",
926                            index
927                        ))?
928                        .clone();
929
930                    interpreter_stack.push_val(ValueAndType::new(value, item_type));
931                    Ok(())
932                }
933                _ => Err("expected a number to select an index from tuple".to_string()),
934            },
935            result => Err(format!(
936                "expected a sequence value or tuple to select an index. But obtained {:?}",
937                result
938            )),
939        }
940    }
941
942    pub(crate) fn run_select_index_instruction(
943        interpreter_stack: &mut InterpreterStack,
944        index: usize,
945    ) -> Result<(), String> {
946        let stack_value = interpreter_stack
947            .pop()
948            .ok_or_else(|| "internal error: failed to get value from the stack".to_string())?;
949
950        match stack_value {
951            RibInterpreterStackValue::Val(ValueAndType {
952                value: Value::List(items),
953                typ: AnalysedType::List(typ),
954            }) => {
955                let value = items
956                    .get(index)
957                    .ok_or_else(|| {
958                        format!(
959                            "index {} is out of bound. list size: {}",
960                            index,
961                            items.len()
962                        )
963                    })?
964                    .clone();
965
966                interpreter_stack.push_val(ValueAndType::new(value, (*typ.inner).clone()));
967                Ok(())
968            }
969            RibInterpreterStackValue::Val(ValueAndType {
970                value: Value::Tuple(items),
971                typ: AnalysedType::Tuple(typ),
972            }) => {
973                let value = items
974                    .get(index)
975                    .ok_or_else(|| format!("Index {} not found in the tuple", index))?
976                    .clone();
977
978                let item_type = typ
979                    .items
980                    .get(index)
981                    .ok_or_else(|| format!("Index {} not found in the tuple type", index))?
982                    .clone();
983
984                interpreter_stack.push_val(ValueAndType::new(value, item_type));
985                Ok(())
986            }
987            result => Err(format!(
988                "Expected a sequence value or tuple to select an index. But obtained {:?}",
989                result
990            )),
991        }
992    }
993
994    pub(crate) fn run_push_enum_instruction(
995        interpreter_stack: &mut InterpreterStack,
996        enum_name: String,
997        analysed_type: AnalysedType,
998    ) -> Result<(), String> {
999        match analysed_type {
1000            AnalysedType::Enum(typed_enum) => {
1001                interpreter_stack.push_enum(enum_name, typed_enum.cases)?;
1002                Ok(())
1003            }
1004            _ => Err(format!(
1005                "Expected a enum type for {}, but obtained {:?}",
1006                enum_name, analysed_type
1007            )),
1008        }
1009    }
1010
1011    pub(crate) async fn run_variant_construction_instruction(
1012        variant_name: String,
1013        analysed_type: AnalysedType,
1014        interpreter_stack: &mut InterpreterStack,
1015    ) -> Result<(), String> {
1016        match analysed_type {
1017            AnalysedType::Variant(variants) => {
1018                let variant = variants
1019                    .cases
1020                    .iter()
1021                    .find(|name| name.name == variant_name)
1022                    .ok_or_else(|| format!("unknown variant {} not found", variant_name))?;
1023
1024                let variant_arg_typ = variant.typ.clone();
1025
1026                let arg_value = match variant_arg_typ {
1027                    Some(_) => Some(interpreter_stack.try_pop_val()?),
1028                    None => None,
1029                };
1030
1031                interpreter_stack.push_variant(
1032                    variant_name.clone(),
1033                    arg_value.map(|vnt| vnt.value),
1034                    variants.cases.clone(),
1035                )
1036            }
1037
1038            _ => Err(format!(
1039                "internal error: expected a variant type for {}, but obtained {:?}",
1040                variant_name, analysed_type
1041            )),
1042        }
1043    }
1044
1045    pub(crate) fn run_create_function_name_instruction(
1046        site: ParsedFunctionSite,
1047        function_type: FunctionReferenceType,
1048        interpreter_stack: &mut InterpreterStack,
1049    ) -> Result<(), String> {
1050        match function_type {
1051            FunctionReferenceType::Function { function } => {
1052                let parsed_function_name = ParsedFunctionName {
1053                    site,
1054                    function: ParsedFunctionReference::Function { function },
1055                };
1056
1057                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1058            }
1059
1060            FunctionReferenceType::RawResourceConstructor { resource } => {
1061                let parsed_function_name = ParsedFunctionName {
1062                    site,
1063                    function: ParsedFunctionReference::RawResourceConstructor { resource },
1064                };
1065
1066                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1067            }
1068            FunctionReferenceType::RawResourceDrop { resource } => {
1069                let parsed_function_name = ParsedFunctionName {
1070                    site,
1071                    function: ParsedFunctionReference::RawResourceDrop { resource },
1072                };
1073
1074                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1075            }
1076            FunctionReferenceType::RawResourceMethod { resource, method } => {
1077                let parsed_function_name = ParsedFunctionName {
1078                    site,
1079                    function: ParsedFunctionReference::RawResourceMethod { resource, method },
1080                };
1081
1082                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1083            }
1084            FunctionReferenceType::RawResourceStaticMethod { resource, method } => {
1085                let parsed_function_name = ParsedFunctionName {
1086                    site,
1087                    function: ParsedFunctionReference::RawResourceStaticMethod { resource, method },
1088                };
1089
1090                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1091            }
1092            FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => {
1093                let last_n_elements = interpreter_stack
1094                    .pop_n(arg_size)
1095                    .ok_or_else(|| "Failed to get values from the stack".to_string())?;
1096
1097                let parameter_values = last_n_elements
1098                    .iter()
1099                    .map(|interpreter_result| {
1100                        interpreter_result.get_val().ok_or_else(|| {
1101                            "internal error: failed to construct resource".to_string()
1102                        })
1103                    })
1104                    .collect::<Result<Vec<ValueAndType>, String>>()?;
1105
1106                let parsed_function_name = ParsedFunctionName {
1107                    site,
1108                    function: ParsedFunctionReference::IndexedResourceConstructor {
1109                        resource,
1110                        resource_params: parameter_values
1111                            .iter()
1112                            .map(print_value_and_type)
1113                            .collect::<Result<Vec<String>, String>>()?,
1114                    },
1115                };
1116
1117                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1118            }
1119            FunctionReferenceType::IndexedResourceMethod {
1120                resource,
1121                arg_size,
1122                method,
1123            } => {
1124                let last_n_elements = interpreter_stack
1125                    .pop_n(arg_size)
1126                    .ok_or_else(|| "Failed to get values from the stack".to_string())?;
1127
1128                let param_values = last_n_elements
1129                    .iter()
1130                    .map(|interpreter_result| {
1131                        interpreter_result.get_val().ok_or_else(|| {
1132                            "internal error: failed to call indexed resource method".to_string()
1133                        })
1134                    })
1135                    .collect::<Result<Vec<ValueAndType>, String>>()?;
1136
1137                let parsed_function_name = ParsedFunctionName {
1138                    site,
1139                    function: ParsedFunctionReference::IndexedResourceMethod {
1140                        resource,
1141                        resource_params: param_values
1142                            .iter()
1143                            .map(print_value_and_type)
1144                            .collect::<Result<Vec<String>, String>>()?,
1145                        method,
1146                    },
1147                };
1148
1149                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1150            }
1151            FunctionReferenceType::IndexedResourceStaticMethod {
1152                resource,
1153                arg_size,
1154                method,
1155            } => {
1156                let last_n_elements = interpreter_stack.pop_n(arg_size).ok_or_else(|| {
1157                    "internal error: Failed to get arguments for static resource method".to_string()
1158                })?;
1159
1160                let param_values = last_n_elements
1161                    .iter()
1162                    .map(|interpreter_result| {
1163                        interpreter_result.get_val().ok_or_else(|| {
1164                            "internal error: Failed to call static resource method".to_string()
1165                        })
1166                    })
1167                    .collect::<Result<Vec<ValueAndType>, String>>()?;
1168
1169                let parsed_function_name = ParsedFunctionName {
1170                    site,
1171                    function: ParsedFunctionReference::IndexedResourceStaticMethod {
1172                        resource,
1173                        resource_params: param_values
1174                            .iter()
1175                            .map(print_value_and_type)
1176                            .collect::<Result<Vec<String>, String>>()?,
1177                        method,
1178                    },
1179                };
1180
1181                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1182            }
1183            FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => {
1184                let last_n_elements = interpreter_stack.pop_n(arg_size).ok_or_else(|| {
1185                    "internal error: failed to get resource parameters for indexed resource drop"
1186                        .to_string()
1187                })?;
1188
1189                let param_values = last_n_elements
1190                    .iter()
1191                    .map(|interpreter_result| {
1192                        interpreter_result.get_val().ok_or_else(|| {
1193                            "internal error: failed to call indexed resource drop".to_string()
1194                        })
1195                    })
1196                    .collect::<Result<Vec<ValueAndType>, String>>()?;
1197
1198                let parsed_function_name = ParsedFunctionName {
1199                    site,
1200                    function: ParsedFunctionReference::IndexedResourceDrop {
1201                        resource,
1202                        resource_params: param_values
1203                            .iter()
1204                            .map(print_value_and_type)
1205                            .collect::<Result<Vec<String>, String>>()?,
1206                    },
1207                };
1208
1209                interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type());
1210            }
1211        }
1212
1213        Ok(())
1214    }
1215
1216    pub(crate) async fn run_call_instruction(
1217        arg_size: usize,
1218        worker_type: WorkerNamePresence,
1219        interpreter_stack: &mut InterpreterStack,
1220        interpreter_env: &mut InterpreterEnv,
1221    ) -> Result<(), String> {
1222        let function_name = interpreter_stack
1223            .pop_str()
1224            .ok_or_else(|| "internal error: failed to get a function name".to_string())?;
1225
1226        let worker_name = match worker_type {
1227            WorkerNamePresence::Present => {
1228                let worker_name = interpreter_stack
1229                    .pop_str()
1230                    .ok_or_else(|| "internal error: failed to get the worker name".to_string())?;
1231
1232                Some(worker_name.clone())
1233            }
1234            WorkerNamePresence::Absent => None,
1235        };
1236
1237        let last_n_elements = interpreter_stack.pop_n(arg_size).ok_or_else(|| {
1238            "internal error: failed to get arguments for the function call".to_string()
1239        })?;
1240
1241        let parameter_values = last_n_elements
1242            .iter()
1243            .map(|interpreter_result| {
1244                interpreter_result.get_val().ok_or_else(|| {
1245                    format!("internal error: failed to call function {}", function_name)
1246                })
1247            })
1248            .collect::<Result<Vec<ValueAndType>, String>>()?;
1249
1250        let result = interpreter_env
1251            .invoke_worker_function_async(worker_name, function_name, parameter_values)
1252            .await?;
1253
1254        let interpreter_result = match result {
1255            ValueAndType {
1256                value: Value::Tuple(value),
1257                ..
1258            } if value.is_empty() => Ok(RibInterpreterStackValue::Unit),
1259            ValueAndType {
1260                value: Value::Tuple(value),
1261                typ: AnalysedType::Tuple(typ),
1262            } if value.len() == 1 => {
1263                let inner_value = value[0].clone();
1264                let inner_type = typ.items[0].clone();
1265                Ok(RibInterpreterStackValue::Val(ValueAndType::new(
1266                    inner_value,
1267                    inner_type,
1268                )))
1269            }
1270            _ => Err("Named multiple results are not supported yet".to_string()),
1271        };
1272
1273        interpreter_stack.push(interpreter_result?);
1274
1275        Ok(())
1276    }
1277    pub(crate) fn run_deconstruct_instruction(
1278        interpreter_stack: &mut InterpreterStack,
1279    ) -> Result<(), String> {
1280        let value = interpreter_stack
1281            .pop()
1282            .ok_or_else(|| "Failed to get a value from the stack to unwrap".to_string())?;
1283
1284        let unwrapped_value = value
1285            .unwrap()
1286            .ok_or_else(|| format!("Failed to unwrap the value {:?}", value))?;
1287
1288        interpreter_stack.push_val(unwrapped_value);
1289        Ok(())
1290    }
1291
1292    pub(crate) fn run_get_tag_instruction(
1293        interpreter_stack: &mut InterpreterStack,
1294    ) -> Result<(), String> {
1295        let value = interpreter_stack
1296            .pop_val()
1297            .ok_or_else(|| "Failed to get a tag value from the stack to unwrap".to_string())?;
1298
1299        let tag = match value {
1300            ValueAndType {
1301                value: Value::Variant { case_idx, .. },
1302                typ: AnalysedType::Variant(typ),
1303            } => typ.cases[case_idx as usize].name.clone(),
1304            ValueAndType {
1305                value: Value::Option(option),
1306                ..
1307            } => match option {
1308                Some(_) => "some".to_string(),
1309                None => "none".to_string(),
1310            },
1311            ValueAndType {
1312                value: Value::Result(result_value),
1313                ..
1314            } => match result_value {
1315                Ok(_) => "ok".to_string(),
1316                Err(_) => "err".to_string(),
1317            },
1318            ValueAndType {
1319                value: Value::Enum(idx),
1320                typ: AnalysedType::Enum(typ),
1321            } => typ.cases[idx as usize].clone(),
1322            _ => "untagged".to_string(),
1323        };
1324
1325        interpreter_stack.push_val(tag.into_value_and_type());
1326        Ok(())
1327    }
1328
1329    pub(crate) fn run_create_some_instruction(
1330        interpreter_stack: &mut InterpreterStack,
1331        analysed_type: AnalysedType,
1332    ) -> Result<(), String> {
1333        let value = interpreter_stack.try_pop_val()?;
1334
1335        match analysed_type {
1336            AnalysedType::Option(analysed_type) => {
1337                interpreter_stack.push_some(value.value, analysed_type.inner.deref());
1338                Ok(())
1339            }
1340            _ => Err(format!(
1341                "internal error: expected option type to create `some` value. But obtained {:?}",
1342                analysed_type
1343            )),
1344        }
1345    }
1346
1347    pub(crate) fn run_create_none_instruction(
1348        interpreter_stack: &mut InterpreterStack,
1349        analysed_type: Option<AnalysedType>,
1350    ) -> Result<(), String> {
1351        match analysed_type {
1352            Some(AnalysedType::Option(_)) | None => {
1353                interpreter_stack.push_none(analysed_type);
1354                Ok(())
1355            }
1356            _ => Err(format!(
1357                "internal error: expected option type to create `none` value. But obtained {:?}",
1358                analysed_type
1359            )),
1360        }
1361    }
1362
1363    pub(crate) fn run_create_ok_instruction(
1364        interpreter_stack: &mut InterpreterStack,
1365        analysed_type: AnalysedType,
1366    ) -> Result<(), String> {
1367        let value = interpreter_stack.try_pop_val()?;
1368
1369        match analysed_type {
1370            AnalysedType::Result(TypeResult { ok, err }) => {
1371                interpreter_stack.push_ok(value.value, ok.as_deref(), err.as_deref());
1372                Ok(())
1373            }
1374            _ => Err(format!(
1375                "internal error: expected result type to create `ok` value. But obtained {:?}",
1376                analysed_type
1377            )),
1378        }
1379    }
1380
1381    pub(crate) fn run_create_err_instruction(
1382        interpreter_stack: &mut InterpreterStack,
1383        analysed_type: AnalysedType,
1384    ) -> Result<(), String> {
1385        let value = interpreter_stack.try_pop_val()?;
1386
1387        match analysed_type {
1388            AnalysedType::Result(TypeResult { ok, err }) => {
1389                interpreter_stack.push_err(value.value, ok.as_deref(), err.as_deref());
1390                Ok(())
1391            }
1392            _ => Err(format!(
1393                "internal error: expected result type to create `err` value. But obtained {:?}",
1394                analysed_type
1395            )),
1396        }
1397    }
1398
1399    pub(crate) fn run_concat_instruction(
1400        interpreter_stack: &mut InterpreterStack,
1401        arg_size: usize,
1402    ) -> Result<(), String> {
1403        let value_and_types = interpreter_stack.try_pop_n_val(arg_size)?;
1404
1405        let mut result = String::new();
1406
1407        for val in value_and_types {
1408            match &val.value {
1409                Value::String(s) => {
1410                    // Avoid extra quotes when concatenating strings
1411                    result.push_str(s);
1412                }
1413                Value::Char(char) => {
1414                    // Avoid extra single quotes when concatenating chars
1415                    result.push(*char);
1416                }
1417                _ => {
1418                    result.push_str(&val.to_string());
1419                }
1420            }
1421        }
1422
1423        interpreter_stack.push_val(result.into_value_and_type());
1424
1425        Ok(())
1426    }
1427}
1428
1429#[cfg(test)]
1430mod tests {
1431    use std::collections::HashMap;
1432    use test_r::test;
1433
1434    use super::*;
1435    use crate::interpreter::rib_interpreter::tests::test_utils::{
1436        get_analysed_type_variant, get_metadata_with_enum_and_variant, get_value_and_type,
1437        strip_spaces,
1438    };
1439    use crate::{
1440        compiler, Expr, FunctionTypeRegistry, GlobalVariableTypeSpec, InferredType, InstructionId,
1441        Path, VariableId,
1442    };
1443    use golem_wasm_ast::analysis::analysed_type::{
1444        bool, case, f32, field, list, option, r#enum, record, result, s32, s8, str, tuple, u32,
1445        u64, u8, variant,
1446    };
1447    use golem_wasm_rpc::{parse_value_and_type, IntoValue, IntoValueAndType, Value, ValueAndType};
1448
1449    #[test]
1450    async fn test_interpreter_for_literal() {
1451        let mut interpreter = Interpreter::default();
1452
1453        let instructions = RibByteCode {
1454            instructions: vec![RibIR::PushLit(1i32.into_value_and_type())],
1455        };
1456
1457        let result = interpreter.run(instructions).await.unwrap();
1458        assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type());
1459    }
1460
1461    #[test]
1462    async fn test_interpreter_for_equal_to() {
1463        let mut interpreter = Interpreter::default();
1464
1465        let instructions = RibByteCode {
1466            instructions: vec![
1467                RibIR::PushLit(1i32.into_value_and_type()),
1468                RibIR::PushLit(1u32.into_value_and_type()),
1469                RibIR::EqualTo,
1470            ],
1471        };
1472
1473        let result = interpreter.run(instructions).await.unwrap();
1474        assert!(result.get_bool().unwrap());
1475    }
1476
1477    #[test]
1478    async fn test_interpreter_for_greater_than() {
1479        let mut interpreter = Interpreter::default();
1480
1481        let instructions = RibByteCode {
1482            instructions: vec![
1483                RibIR::PushLit(1i32.into_value_and_type()),
1484                RibIR::PushLit(2u32.into_value_and_type()),
1485                RibIR::GreaterThan,
1486            ],
1487        };
1488
1489        let result = interpreter.run(instructions).await.unwrap();
1490        assert!(result.get_bool().unwrap());
1491    }
1492
1493    #[test]
1494    async fn test_interpreter_for_less_than() {
1495        let mut interpreter = Interpreter::default();
1496
1497        let instructions = RibByteCode {
1498            instructions: vec![
1499                RibIR::PushLit(2i32.into_value_and_type()),
1500                RibIR::PushLit(1u32.into_value_and_type()),
1501                RibIR::LessThan,
1502            ],
1503        };
1504
1505        let result = interpreter.run(instructions).await.unwrap();
1506        assert!(result.get_bool().unwrap());
1507    }
1508
1509    #[test]
1510    async fn test_interpreter_for_greater_than_or_equal_to() {
1511        let mut interpreter = Interpreter::default();
1512
1513        let instructions = RibByteCode {
1514            instructions: vec![
1515                RibIR::PushLit(2i32.into_value_and_type()),
1516                RibIR::PushLit(3u32.into_value_and_type()),
1517                RibIR::GreaterThanOrEqualTo,
1518            ],
1519        };
1520
1521        let result = interpreter.run(instructions).await.unwrap();
1522        assert!(result.get_bool().unwrap());
1523    }
1524
1525    #[test]
1526    async fn test_interpreter_for_less_than_or_equal_to() {
1527        let mut interpreter = Interpreter::default();
1528
1529        let instructions = RibByteCode {
1530            instructions: vec![
1531                RibIR::PushLit(2i32.into_value_and_type()), // rhs
1532                RibIR::PushLit(1i32.into_value_and_type()), // lhs
1533                RibIR::LessThanOrEqualTo,
1534            ],
1535        };
1536
1537        let result = interpreter.run(instructions).await.unwrap();
1538        assert!(result.get_bool().unwrap());
1539    }
1540
1541    #[test]
1542    async fn test_interpreter_for_assign_and_load_var() {
1543        let mut interpreter = Interpreter::default();
1544
1545        let instructions = RibByteCode {
1546            instructions: vec![
1547                RibIR::PushLit(1i32.into_value_and_type()),
1548                RibIR::AssignVar(VariableId::local_with_no_id("x")),
1549                RibIR::LoadVar(VariableId::local_with_no_id("x")),
1550            ],
1551        };
1552
1553        let result = interpreter.run(instructions).await.unwrap();
1554        assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type());
1555    }
1556
1557    #[test]
1558    async fn test_interpreter_for_jump() {
1559        let mut interpreter = Interpreter::default();
1560
1561        let instructions = RibByteCode {
1562            instructions: vec![
1563                RibIR::Jump(InstructionId::init()),
1564                RibIR::PushLit(1i32.into_value_and_type()),
1565                RibIR::Label(InstructionId::init()),
1566            ],
1567        };
1568
1569        let result = interpreter.run(instructions).await;
1570        assert!(result.is_ok());
1571    }
1572
1573    #[test]
1574    async fn test_interpreter_for_jump_if_false() {
1575        let mut interpreter = Interpreter::default();
1576
1577        let id = InstructionId::init().increment_mut();
1578
1579        let instructions = RibByteCode {
1580            instructions: vec![
1581                RibIR::PushLit(false.into_value_and_type()),
1582                RibIR::JumpIfFalse(id.clone()),
1583                RibIR::PushLit(1i32.into_value_and_type()),
1584                RibIR::Label(id),
1585            ],
1586        };
1587
1588        let result = interpreter.run(instructions).await;
1589        assert!(result.is_ok());
1590    }
1591
1592    #[test]
1593    async fn test_interpreter_for_record() {
1594        let mut interpreter = Interpreter::default();
1595
1596        let instructions = RibByteCode {
1597            instructions: vec![
1598                RibIR::PushLit(2i32.into_value_and_type()),
1599                RibIR::PushLit(1i32.into_value_and_type()),
1600                RibIR::CreateAndPushRecord(record(vec![field("x", s32()), field("y", s32())])),
1601                RibIR::UpdateRecord("x".to_string()),
1602                RibIR::UpdateRecord("y".to_string()),
1603            ],
1604        };
1605
1606        let result = interpreter.run(instructions).await.unwrap();
1607        let expected = ValueAndType::new(
1608            Value::Record(vec![1i32.into_value(), 2i32.into_value()]),
1609            record(vec![field("x", s32()), field("y", s32())]),
1610        );
1611
1612        assert_eq!(result.get_val().unwrap(), expected);
1613    }
1614
1615    #[test]
1616    async fn test_interpreter_for_sequence() {
1617        let mut interpreter = Interpreter::default();
1618
1619        let instructions = RibByteCode {
1620            instructions: vec![
1621                RibIR::PushLit(2i32.into_value_and_type()),
1622                RibIR::PushLit(1i32.into_value_and_type()),
1623                RibIR::PushList(list(s32()), 2),
1624            ],
1625        };
1626
1627        let result = interpreter.run(instructions).await.unwrap();
1628        let expected = ValueAndType::new(
1629            Value::List(vec![1i32.into_value(), 2i32.into_value()]),
1630            list(s32()),
1631        );
1632        assert_eq!(result.get_val().unwrap(), expected);
1633    }
1634
1635    #[test]
1636    async fn test_interpreter_for_select_field() {
1637        let mut interpreter = Interpreter::default();
1638
1639        let instructions = RibByteCode {
1640            instructions: vec![
1641                RibIR::PushLit(1i32.into_value_and_type()),
1642                RibIR::PushLit(2i32.into_value_and_type()),
1643                RibIR::CreateAndPushRecord(record(vec![field("x", s32())])),
1644                RibIR::UpdateRecord("x".to_string()),
1645                RibIR::SelectField("x".to_string()),
1646            ],
1647        };
1648
1649        let result = interpreter.run(instructions).await.unwrap();
1650        assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type());
1651    }
1652
1653    #[test]
1654    async fn test_interpreter_for_select_index() {
1655        let mut interpreter = Interpreter::default();
1656
1657        let instructions = RibByteCode {
1658            instructions: vec![
1659                RibIR::PushLit(1i32.into_value_and_type()),
1660                RibIR::PushLit(2i32.into_value_and_type()),
1661                RibIR::PushList(list(s32()), 2),
1662                RibIR::SelectIndex(0),
1663            ],
1664        };
1665
1666        let result = interpreter.run(instructions).await.unwrap();
1667        assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type());
1668    }
1669
1670    #[test]
1671    async fn test_interpreter_variable_scope_0() {
1672        let rib_expr = r#"
1673               let x: u64 = 1;
1674               let y = x + 2u64;
1675               y
1676            "#;
1677
1678        let expr = Expr::from_text(rib_expr).unwrap();
1679
1680        let compiled = compiler::compile(expr, &vec![]).unwrap();
1681
1682        let mut interpreter = Interpreter::default();
1683
1684        let result = interpreter.run(compiled.byte_code).await.unwrap();
1685
1686        assert_eq!(result.get_val().unwrap(), 3u64.into_value_and_type());
1687    }
1688
1689    #[test]
1690    async fn test_interpreter_variable_scope_1() {
1691        let rib_expr = r#"
1692               let x: u64 = 1;
1693               let z = {foo : x};
1694               let x = x + 2u64;
1695               { bar: x, baz: z }
1696            "#;
1697
1698        let expr = Expr::from_text(rib_expr).unwrap();
1699
1700        let compiled = compiler::compile(expr, &vec![]).unwrap();
1701
1702        let mut interpreter = Interpreter::default();
1703
1704        let result = interpreter.run(compiled.byte_code).await.unwrap();
1705
1706        let analysed_type = record(vec![
1707            field("bar", u64()),
1708            field("baz", record(vec![field("foo", u64())])),
1709        ]);
1710
1711        let expected = get_value_and_type(&analysed_type, r#"{ bar: 3, baz: { foo: 1 } }"#);
1712
1713        assert_eq!(result.get_val().unwrap(), expected);
1714    }
1715
1716    #[test]
1717    async fn test_interpreter_variable_scope_2() {
1718        let rib_expr = r#"
1719               let x: u64 = 1;
1720               let x = x;
1721
1722               let result1 = match some(x + 1:u64) {
1723                  some(x) => x,
1724                  none => x
1725               };
1726
1727               let z: option<u64> = none;
1728
1729               let result2 = match z {
1730                  some(x) => x,
1731                  none => x
1732               };
1733
1734               { result1: result1, result2: result2 }
1735            "#;
1736
1737        let expr = Expr::from_text(rib_expr).unwrap();
1738
1739        let compiled = compiler::compile(expr, &vec![]).unwrap();
1740
1741        let mut interpreter = Interpreter::default();
1742
1743        let result = interpreter.run(compiled.byte_code).await.unwrap();
1744
1745        let analysed_type = record(vec![field("result1", u64()), field("result2", u64())]);
1746
1747        let expected = get_value_and_type(&analysed_type, r#"{ result1: 2, result2: 1 }"#);
1748
1749        assert_eq!(result.get_val().unwrap(), expected);
1750    }
1751
1752    #[test]
1753    async fn test_interpreter_variable_scope_3() {
1754        let rib_expr = r#"
1755               let x: u64 = 1;
1756               let x = x;
1757
1758               let result1 = match some(x + 1:u64) {
1759                  some(x) => match some(x + 1:u64) {
1760                     some(x) => x,
1761                     none => x
1762                  },
1763                  none => x
1764               };
1765
1766               let z: option<u64> = none;
1767
1768               let result2 = match z {
1769                  some(x) => x,
1770                  none => match some(x + 1:u64) {
1771                     some(x) => x,
1772                     none => x
1773                  }
1774               };
1775
1776               { result1: result1, result2: result2 }
1777            "#;
1778
1779        let expr = Expr::from_text(rib_expr).unwrap();
1780
1781        let compiled = compiler::compile(expr, &vec![]).unwrap();
1782
1783        let mut interpreter = Interpreter::default();
1784
1785        let result = interpreter.run(compiled.byte_code).await.unwrap();
1786
1787        let analysed_type = record(vec![field("result1", u64()), field("result2", u64())]);
1788
1789        let expected = get_value_and_type(&analysed_type, r#"{ result1: 3, result2: 2 }"#);
1790
1791        assert_eq!(result.get_val().unwrap(), expected);
1792    }
1793
1794    #[test]
1795    async fn test_interpreter_global_variable_with_type_spec() {
1796        // request.path.user-id and request.headers.* should be inferred as string,
1797        // since we configure the compiler with a type-spec (given below)
1798        let rib_expr = r#"
1799               let res1 = request.path.user-id;
1800               let res2 = request.headers.name;
1801               let res3 = request.headers.age;
1802               "${res1}-${res2}-${res3}"
1803            "#;
1804
1805        let type_spec = vec![
1806            GlobalVariableTypeSpec {
1807                variable_id: VariableId::global("request".to_string()),
1808                path: Path::from_elems(vec!["path"]),
1809                inferred_type: InferredType::Str,
1810            },
1811            GlobalVariableTypeSpec {
1812                variable_id: VariableId::global("request".to_string()),
1813                path: Path::from_elems(vec!["headers"]),
1814                inferred_type: InferredType::Str,
1815            },
1816        ];
1817
1818        let mut rib_input = HashMap::new();
1819
1820        // Rib compiler identifies the input requirements to be a string (due to type-spec passed)
1821        // and therefore, we pass input value (value_and_type) to the interpreter with headers and path values as string
1822        let analysed_type_of_input = &record(vec![
1823            field("path", record(vec![field("user-id", str())])),
1824            field(
1825                "headers",
1826                record(vec![field("name", str()), field("age", str())]),
1827            ),
1828        ]);
1829
1830        let value_and_type = get_value_and_type(
1831            analysed_type_of_input,
1832            r#"{path : { user-id: "1" }, headers: { name: "foo", age: "20" }}"#,
1833        );
1834
1835        rib_input.insert("request".to_string(), value_and_type);
1836
1837        let mut interpreter = test_utils::interpreter_static_response(
1838            &ValueAndType::new(Value::S8(1), s8()),
1839            Some(RibInput::new(rib_input)),
1840        );
1841
1842        let expr = Expr::from_text(rib_expr).unwrap();
1843
1844        let compiled =
1845            compiler::compile_with_restricted_global_variables(expr, &vec![], None, &type_spec)
1846                .unwrap();
1847
1848        let result = interpreter
1849            .run(compiled.byte_code)
1850            .await
1851            .unwrap()
1852            .get_val()
1853            .unwrap()
1854            .value;
1855
1856        assert_eq!(result, Value::String("1-foo-20".to_string()))
1857    }
1858
1859    #[test]
1860    async fn test_interpreter_global_variable_override_type_spec() {
1861        let rib_expr = r#"
1862             let res1: u32 = request.path.user-id;
1863             let res2 = request.headers.name;
1864             let res3: u32 = request.headers.age;
1865             let res4 = res1 + res3;
1866             "${res4}-${res2}"
1867            "#;
1868
1869        // We always specify the type of request.path.* and request.headers.* to be a string using type-spec
1870        // however the rib script (above) explicitly specify the type of request.path.user-id
1871        // and request.header.age to be u32. In this case, the Rib compiler infer them as u32 and interpreter works with u32.
1872        let type_spec = vec![
1873            GlobalVariableTypeSpec {
1874                variable_id: VariableId::global("request".to_string()),
1875                path: Path::from_elems(vec!["path"]),
1876                inferred_type: InferredType::Str,
1877            },
1878            GlobalVariableTypeSpec {
1879                variable_id: VariableId::global("request".to_string()),
1880                path: Path::from_elems(vec!["headers"]),
1881                inferred_type: InferredType::Str,
1882            },
1883        ];
1884
1885        let mut rib_input = HashMap::new();
1886
1887        // We pass the input value to rib-interpreter with request.path.user-id
1888        // and request.headers.age as u32, since the compiler inferred these input type requirements to be u32.
1889        let analysed_type_of_input = &record(vec![
1890            field("path", record(vec![field("user-id", u32())])),
1891            field(
1892                "headers",
1893                record(vec![field("name", str()), field("age", u32())]),
1894            ),
1895        ]);
1896
1897        let value_and_type = get_value_and_type(
1898            analysed_type_of_input,
1899            r#"{path : { user-id: 1 }, headers: { name: "foo", age: 20 }}"#,
1900        );
1901
1902        rib_input.insert("request".to_string(), value_and_type);
1903
1904        let mut interpreter = test_utils::interpreter_static_response(
1905            &ValueAndType::new(Value::S8(1), s8()),
1906            Some(RibInput::new(rib_input)),
1907        );
1908
1909        let expr = Expr::from_text(rib_expr).unwrap();
1910
1911        let compiled =
1912            compiler::compile_with_restricted_global_variables(expr, &vec![], None, &type_spec)
1913                .unwrap();
1914
1915        let result = interpreter
1916            .run(compiled.byte_code)
1917            .await
1918            .unwrap()
1919            .get_val()
1920            .unwrap()
1921            .value;
1922
1923        assert_eq!(result, Value::String("21-foo".to_string()))
1924    }
1925
1926    #[test]
1927    async fn test_interpreter_concatenation() {
1928        let mut interpreter = test_utils::interpreter_dynamic_response(None);
1929
1930        let rib_expr = r#"
1931            let x = "foo";
1932            let y = "bar";
1933            let z = {foo: "baz"};
1934            let n: u32 = 42;
1935            let result = "${x}-${y}-${z}-${n}";
1936            result
1937        "#;
1938
1939        let expr = Expr::from_text(rib_expr).unwrap();
1940        let compiled = compiler::compile(expr, &vec![]).unwrap();
1941        let result = interpreter.run(compiled.byte_code).await.unwrap();
1942
1943        assert_eq!(
1944            result.get_val().unwrap().value,
1945            Value::String("foo-bar-{foo: \"baz\"}-42".to_string())
1946        );
1947    }
1948
1949    #[test]
1950    async fn test_interpreter_with_variant_and_enum() {
1951        let mut interpreter = test_utils::interpreter_dynamic_response(None);
1952
1953        // This has intentionally got conflicting variable names
1954        // variable `x` is same as the enum name `x`
1955        // similarly, variably `validate` is same as the variant name validate
1956        let expr = r#"
1957          let x = x;
1958          let y = x;
1959          let result1 = add-enum(x, y);
1960          let validate = validate;
1961          let validate2 = validate;
1962          let result2 = add-variant(validate, validate2);
1963          {res1: result1, res2: result2}
1964        "#;
1965
1966        let expr = Expr::from_text(expr).unwrap();
1967        let compiled = compiler::compile(expr, &get_metadata_with_enum_and_variant()).unwrap();
1968        let result = interpreter.run(compiled.byte_code).await.unwrap();
1969        let expected_enum_type = r#enum(&["x", "y", "z"]);
1970        let expected_variant_type = get_analysed_type_variant();
1971
1972        let expected_record_type = record(vec![
1973            field("res1", expected_enum_type),
1974            field("res2", expected_variant_type),
1975        ]);
1976
1977        let expected_record_value = Value::Record(vec![
1978            Value::Enum(0),
1979            Value::Variant {
1980                case_idx: 2,
1981                case_value: None,
1982            },
1983        ]);
1984
1985        assert_eq!(
1986            result,
1987            RibResult::Val(ValueAndType::new(
1988                expected_record_value,
1989                expected_record_type
1990            ))
1991        );
1992    }
1993
1994    #[test]
1995    async fn test_interpreter_with_conflicting_variable_names() {
1996        let mut interpreter = test_utils::interpreter_dynamic_response(None);
1997
1998        // This has intentionally conflicting variable names
1999        // variable `x` is same as the enum name `x`
2000        // similarly, variably `validate` is same as the variant name `validate`
2001        // and `process-user` is same as the variant name `process-user`
2002        let expr = r#"
2003          let x = 1;
2004          let y = 2;
2005          let result1 = add-u32(x, y);
2006          let process-user = 3;
2007          let validate = 4;
2008          let result2 = add-u64(process-user, validate);
2009          {res1: result1, res2: result2}
2010        "#;
2011
2012        let expr = Expr::from_text(expr).unwrap();
2013        let compiled = compiler::compile(expr, &get_metadata_with_enum_and_variant()).unwrap();
2014        let result = interpreter.run(compiled.byte_code).await.unwrap();
2015        let expected_value = Value::Record(vec![3u32.into_value(), 7u64.into_value()]);
2016
2017        let expected_type = record(vec![field("res1", u32()), field("res2", u64())]);
2018        assert_eq!(
2019            result,
2020            RibResult::Val(ValueAndType::new(expected_value, expected_type))
2021        );
2022    }
2023
2024    #[test]
2025    async fn test_interpreter_list_reduce() {
2026        let mut interpreter = Interpreter::default();
2027
2028        let rib_expr = r#"
2029          let x: list<u8> = [1, 2];
2030
2031          reduce z, a in x from 0u8 {
2032            yield z + a;
2033          }
2034
2035          "#;
2036
2037        let expr = Expr::from_text(rib_expr).unwrap();
2038
2039        let compiled = compiler::compile(expr, &vec![]).unwrap();
2040
2041        let result = interpreter
2042            .run(compiled.byte_code)
2043            .await
2044            .unwrap()
2045            .get_val()
2046            .unwrap();
2047
2048        assert_eq!(result, 3u8.into_value_and_type());
2049    }
2050
2051    #[test]
2052    async fn test_interpreter_list_reduce_from_record() {
2053        let mut interpreter = Interpreter::default();
2054
2055        let rib_expr = r#"
2056           let x = [{name: "foo", age: 1u64}, {name: "bar", age: 2u64}];
2057
2058           let names = for i in x {
2059             yield i.name;
2060           };
2061
2062          reduce z, a in names from "" {
2063            let result = if z == "" then a else "${z}, ${a}";
2064
2065            yield result;
2066          }
2067
2068          "#;
2069
2070        let expr = Expr::from_text(rib_expr).unwrap();
2071
2072        let compiled = compiler::compile(expr, &vec![]).unwrap();
2073
2074        let result = interpreter
2075            .run(compiled.byte_code)
2076            .await
2077            .unwrap()
2078            .get_val()
2079            .unwrap();
2080
2081        assert_eq!(result, "foo, bar".into_value_and_type());
2082    }
2083
2084    #[test]
2085    async fn test_interpreter_list_reduce_text() {
2086        let mut interpreter = Interpreter::default();
2087
2088        let rib_expr = r#"
2089           let x = ["foo", "bar"];
2090
2091          reduce z, a in x from "" {
2092            let result = if z == "" then a else "${z}, ${a}";
2093
2094            yield result;
2095          }
2096
2097          "#;
2098
2099        let expr = Expr::from_text(rib_expr).unwrap();
2100
2101        let compiled = compiler::compile(expr, &vec![]).unwrap();
2102
2103        let result = interpreter
2104            .run(compiled.byte_code)
2105            .await
2106            .unwrap()
2107            .get_val()
2108            .unwrap();
2109
2110        assert_eq!(result, "foo, bar".into_value_and_type());
2111    }
2112
2113    #[test]
2114    async fn test_interpreter_list_reduce_empty() {
2115        let mut interpreter = Interpreter::default();
2116
2117        let rib_expr = r#"
2118          let x: list<u8> = [];
2119
2120          reduce z, a in x from 0u8 {
2121            yield z + a;
2122          }
2123
2124          "#;
2125
2126        let expr = Expr::from_text(rib_expr).unwrap();
2127
2128        let compiled = compiler::compile(expr, &vec![]).unwrap();
2129
2130        let result = interpreter
2131            .run(compiled.byte_code)
2132            .await
2133            .unwrap()
2134            .get_val()
2135            .unwrap();
2136
2137        assert_eq!(result, 0u8.into_value_and_type());
2138    }
2139
2140    #[test]
2141    async fn test_interpreter_with_numbers_1() {
2142        let component_metadata =
2143            test_utils::get_component_metadata("foo", vec![u32()], Some(u64()));
2144
2145        let mut interpreter =
2146            test_utils::interpreter_static_response(&ValueAndType::new(Value::U64(2), u64()), None);
2147
2148        // 1 is automatically inferred to be u32
2149        let rib = r#"
2150          let worker = instance("my-worker");
2151          worker.foo(1)
2152        "#;
2153
2154        let expr = Expr::from_text(rib).unwrap();
2155        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2156        let result = interpreter.run(compiled.byte_code).await.unwrap();
2157
2158        assert_eq!(
2159            result.get_val().unwrap(),
2160            ValueAndType::new(Value::U64(2), u64())
2161        );
2162    }
2163
2164    #[test]
2165    async fn test_interpreter_with_numbers_2() {
2166        let component_metadata =
2167            test_utils::get_component_metadata("foo", vec![u32()], Some(u64()));
2168
2169        let mut interpreter =
2170            test_utils::interpreter_static_response(&ValueAndType::new(Value::U64(2), u64()), None);
2171
2172        // 1 and 2 are automatically inferred to be u32
2173        // since the type of z is inferred to be u32 as that being passed to a function
2174        // that expects u32
2175        let rib = r#"
2176          let worker = instance("my-worker");
2177          let z = 1 + 2;
2178          worker.foo(z)
2179        "#;
2180
2181        let expr = Expr::from_text(rib).unwrap();
2182        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2183        let result = interpreter.run(compiled.byte_code).await.unwrap();
2184
2185        assert_eq!(
2186            result.get_val().unwrap(),
2187            ValueAndType::new(Value::U64(2), u64())
2188        );
2189    }
2190
2191    #[test]
2192    async fn test_interpreter_with_numbers_3() {
2193        let component_metadata =
2194            test_utils::get_component_metadata("foo", vec![u32()], Some(u64()));
2195
2196        // This will cause a type inference error
2197        // because the operands of the + operator are not of the same type
2198        let rib = r#"
2199          let worker = instance("my-worker");
2200          let z = 1: u8 + 2;
2201          worker.foo(z)
2202        "#;
2203
2204        let expr = Expr::from_text(rib).unwrap();
2205        let compile_result = compiler::compile(expr, &component_metadata);
2206        assert!(compile_result.is_err());
2207    }
2208
2209    #[test]
2210    async fn test_interpreter_with_numbers_4() {
2211        let component_metadata =
2212            test_utils::get_component_metadata("foo", vec![u32()], Some(u64()));
2213
2214        // This will cause a type inference error
2215        // because the operands of the + operator are supposed to be u32
2216        // since z is u32
2217        let rib = r#"
2218          let worker = instance("my-worker");
2219          let z = 1: u8 + 2: u8;
2220          worker.foo(z)
2221        "#;
2222
2223        let expr = Expr::from_text(rib).unwrap();
2224        let compile_result = compiler::compile(expr, &component_metadata);
2225        assert!(compile_result.is_err());
2226    }
2227
2228    #[test]
2229    async fn test_interpreter_list_comprehension() {
2230        let mut interpreter = Interpreter::default();
2231
2232        let rib_expr = r#"
2233          let x = ["foo", "bar"];
2234
2235          for i in x {
2236            yield i;
2237          }
2238
2239          "#;
2240
2241        let expr = Expr::from_text(rib_expr).unwrap();
2242
2243        let compiled = compiler::compile(expr, &vec![]).unwrap();
2244
2245        let result = interpreter
2246            .run(compiled.byte_code)
2247            .await
2248            .unwrap()
2249            .get_val()
2250            .unwrap();
2251
2252        let expected = r#"["foo", "bar"]"#;
2253        let expected_value = golem_wasm_rpc::parse_value_and_type(&list(str()), expected).unwrap();
2254
2255        assert_eq!(result, expected_value);
2256    }
2257
2258    #[test]
2259    async fn test_interpreter_list_comprehension_empty() {
2260        let mut interpreter = Interpreter::default();
2261
2262        let rib_expr = r#"
2263          let x: list<string> = [];
2264
2265          for i in x {
2266            yield i;
2267          }
2268
2269          "#;
2270
2271        let expr = Expr::from_text(rib_expr).unwrap();
2272
2273        let compiled = compiler::compile(expr, &vec![]).unwrap();
2274
2275        let result = interpreter
2276            .run(compiled.byte_code)
2277            .await
2278            .unwrap()
2279            .get_val()
2280            .unwrap();
2281
2282        let expected = r#"[]"#;
2283        let expected_value_and_type =
2284            golem_wasm_rpc::parse_value_and_type(&list(str()), expected).unwrap();
2285
2286        assert_eq!(result, expected_value_and_type);
2287    }
2288
2289    #[test]
2290    async fn test_interpreter_pattern_match_on_option_nested() {
2291        let mut interpreter = Interpreter::default();
2292
2293        let expr = r#"
2294           let x: option<option<u64>> = none;
2295
2296           match x {
2297              some(some(t)) => t,
2298              some(none) => 0u64,
2299              none => 0u64
2300
2301           }
2302        "#;
2303
2304        let mut expr = Expr::from_text(expr).unwrap();
2305        expr.infer_types(&FunctionTypeRegistry::empty(), &vec![])
2306            .unwrap();
2307        let compiled = compiler::compile(expr, &vec![]).unwrap();
2308        let result = interpreter.run(compiled.byte_code).await.unwrap();
2309
2310        assert_eq!(result.get_val().unwrap(), 0u64.into_value_and_type());
2311    }
2312
2313    #[test]
2314    async fn test_interpreter_pattern_match_on_tuple() {
2315        let mut interpreter = Interpreter::default();
2316
2317        let expr = r#"
2318           let x: tuple<u64, string, string> = (1, "foo", "bar");
2319
2320           match x {
2321              (x, y, z) => "${x} ${y} ${z}"
2322           }
2323        "#;
2324
2325        let mut expr = Expr::from_text(expr).unwrap();
2326        expr.infer_types(&FunctionTypeRegistry::empty(), &vec![])
2327            .unwrap();
2328        let compiled = compiler::compile(expr, &vec![]).unwrap();
2329        let result = interpreter.run(compiled.byte_code).await.unwrap();
2330
2331        assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type());
2332    }
2333
2334    #[test]
2335    async fn test_interpreter_pattern_match_on_tuple_with_option_some() {
2336        let mut interpreter = Interpreter::default();
2337
2338        let expr = r#"
2339           let x: tuple<u64, option<string>, string> = (1, some("foo"), "bar");
2340
2341           match x {
2342              (x, none, z) => "${x} ${z}",
2343              (x, some(y), z) => "${x} ${y} ${z}"
2344           }
2345        "#;
2346
2347        let mut expr = Expr::from_text(expr).unwrap();
2348        expr.infer_types(&FunctionTypeRegistry::empty(), &vec![])
2349            .unwrap();
2350
2351        let compiled = compiler::compile(expr, &vec![]).unwrap();
2352        let result = interpreter.run(compiled.byte_code).await.unwrap();
2353
2354        assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type());
2355    }
2356
2357    #[test]
2358    async fn test_interpreter_pattern_match_on_tuple_with_option_none() {
2359        let mut interpreter = Interpreter::default();
2360
2361        let expr = r#"
2362           let x: tuple<u64, option<string>, string> = (1, none, "bar");
2363
2364           match x {
2365              (x, none, z) => "${x} ${z}",
2366              (x, some(y), z) => "${x} ${y} ${z}"
2367           }
2368        "#;
2369
2370        let expr = Expr::from_text(expr).unwrap();
2371        let compiled = compiler::compile(expr, &vec![]).unwrap();
2372        let result = interpreter.run(compiled.byte_code).await.unwrap();
2373
2374        assert_eq!(result.get_val().unwrap(), "1 bar".into_value_and_type());
2375    }
2376
2377    #[test]
2378    async fn test_interpreter_pattern_match_dynamic_branch_1() {
2379        let mut interpreter = Interpreter::default();
2380
2381        let expr = r#"
2382           let x: u64 = 1;
2383
2384           match x {
2385                1 => ok(1: u64),
2386                2 => err("none")
2387           }
2388        "#;
2389
2390        let expr = Expr::from_text(expr).unwrap();
2391        let compiled = compiler::compile(expr, &vec![]).unwrap();
2392        let rib_result = interpreter.run(compiled.byte_code).await.unwrap();
2393
2394        let expected = ValueAndType::new(
2395            Value::Result(Ok(Some(Box::new(Value::U64(1))))),
2396            result(u64(), str()),
2397        );
2398
2399        assert_eq!(rib_result.get_val().unwrap(), expected);
2400    }
2401
2402    #[test]
2403    async fn test_interpreter_pattern_match_dynamic_branch_2() {
2404        let mut interpreter = Interpreter::default();
2405
2406        let expr = r#"
2407           let x = some({foo: 1:u64});
2408
2409           match x {
2410               some(x) => ok(x.foo),
2411               none => err("none")
2412           }
2413        "#;
2414
2415        let expr = Expr::from_text(expr).unwrap();
2416        let compiled = compiler::compile(expr, &vec![]).unwrap();
2417        let rib_result = interpreter.run(compiled.byte_code).await.unwrap();
2418
2419        let expected = ValueAndType::new(
2420            Value::Result(Ok(Some(Box::new(Value::U64(1))))),
2421            result(u64(), str()),
2422        );
2423
2424        assert_eq!(rib_result.get_val().unwrap(), expected);
2425    }
2426
2427    #[test]
2428    async fn test_interpreter_pattern_match_on_tuple_with_all_types() {
2429        let mut interpreter = Interpreter::default();
2430
2431        let tuple = test_utils::get_analysed_type_tuple();
2432
2433        let analysed_exports = test_utils::get_component_metadata("foo", vec![tuple], Some(str()));
2434
2435        let expr = r#"
2436
2437           let record = { request : { path : { user : "jak" } }, y : "bar" };
2438           let input = (1, ok(100), "bar", record, process-user("jon"), register-user(1u64), validate, prod, dev, test);
2439           foo(input);
2440           match input {
2441             (n1, err(x1), txt, rec, process-user(x), register-user(n), validate, dev, prod, test) =>  "Invalid",
2442             (n1, ok(x2), txt, rec, process-user(x), register-user(n), validate, prod, dev, test) =>  "foo ${x2} ${n1} ${txt} ${rec.request.path.user} ${validate} ${prod} ${dev} ${test}"
2443           }
2444
2445        "#;
2446
2447        let expr = Expr::from_text(expr).unwrap();
2448        let compiled = compiler::compile(expr, &analysed_exports).unwrap();
2449        let result = interpreter.run(compiled.byte_code).await.unwrap();
2450
2451        assert_eq!(
2452            result.get_val().unwrap(),
2453            "foo 100 1 bar jak validate prod dev test".into_value_and_type()
2454        );
2455    }
2456
2457    #[test]
2458    async fn test_interpreter_pattern_match_on_tuple_with_wild_pattern() {
2459        let mut interpreter = Interpreter::default();
2460
2461        let tuple = test_utils::get_analysed_type_tuple();
2462
2463        let analysed_exports =
2464            test_utils::get_component_metadata("my-worker-function", vec![tuple], Some(str()));
2465
2466        let expr = r#"
2467
2468           let record = { request : { path : { user : "jak" } }, y : "baz" };
2469           let input = (1, ok(1), "bar", record, process-user("jon"), register-user(1u64), validate, prod, dev, test);
2470           my-worker-function(input);
2471           match input {
2472             (n1, ok(x), txt, rec, _, _, _, _, prod, _) =>  "prod ${n1} ${txt} ${rec.request.path.user} ${rec.y}",
2473             (n1, ok(x), txt, rec, _, _, _, _, dev, _) =>   "dev ${n1} ${txt} ${rec.request.path.user} ${rec.y}"
2474           }
2475        "#;
2476
2477        let expr = Expr::from_text(expr).unwrap();
2478        let compiled = compiler::compile(expr, &analysed_exports).unwrap();
2479        let result = interpreter.run(compiled.byte_code).await.unwrap();
2480
2481        assert_eq!(
2482            result.get_val().unwrap(),
2483            "dev 1 bar jak baz".into_value_and_type()
2484        );
2485    }
2486
2487    #[test]
2488    async fn test_interpreter_record_output_in_pattern_match() {
2489        let input_analysed_type = test_utils::get_analysed_type_record();
2490        let output_analysed_type = test_utils::get_analysed_type_result();
2491
2492        let result_value = get_value_and_type(&output_analysed_type, r#"ok(1)"#);
2493
2494        let mut interpreter = test_utils::interpreter_static_response(&result_value, None);
2495
2496        let analysed_exports = test_utils::get_component_metadata(
2497            "my-worker-function",
2498            vec![input_analysed_type],
2499            Some(output_analysed_type),
2500        );
2501
2502        let expr = r#"
2503
2504           let input = { request : { path : { user : "jak" } }, y : "baz" };
2505           let result = my-worker-function(input);
2506           match result {
2507             ok(result) => { body: result, status: 200 },
2508             err(result) => { status: 400, body: 400 }
2509           }
2510        "#;
2511
2512        let expr = Expr::from_text(expr).unwrap();
2513        let compiled = compiler::compile(expr, &analysed_exports).unwrap();
2514        let result = interpreter.run(compiled.byte_code).await.unwrap();
2515
2516        let expected = test_utils::get_value_and_type(
2517            &record(vec![field("body", u64()), field("status", u64())]),
2518            r#"{body: 1, status: 200}"#,
2519        );
2520
2521        assert_eq!(result.get_val().unwrap(), expected);
2522    }
2523
2524    #[test]
2525    async fn test_interpreter_tuple_output_in_pattern_match() {
2526        let input_analysed_type = test_utils::get_analysed_type_record();
2527        let output_analysed_type = test_utils::get_analysed_type_result();
2528
2529        let result_value = get_value_and_type(&output_analysed_type, r#"err("failed")"#);
2530
2531        let mut interpreter = test_utils::interpreter_static_response(&result_value, None);
2532
2533        let analysed_exports = test_utils::get_component_metadata(
2534            "my-worker-function",
2535            vec![input_analysed_type],
2536            Some(output_analysed_type),
2537        );
2538
2539        let expr = r#"
2540
2541           let input = { request : { path : { user : "jak" } }, y : "baz" };
2542           let result = my-worker-function(input);
2543           match result {
2544             ok(res) => ("${res}", "foo"),
2545             err(msg) => (msg, "bar")
2546           }
2547        "#;
2548
2549        let expr = Expr::from_text(expr).unwrap();
2550        let compiled = compiler::compile(expr, &analysed_exports).unwrap();
2551        let result = interpreter.run(compiled.byte_code).await.unwrap();
2552
2553        let expected = get_value_and_type(&tuple(vec![str(), str()]), r#"("failed", "bar")"#);
2554
2555        assert_eq!(result.get_val().unwrap(), expected);
2556    }
2557
2558    #[test]
2559    async fn test_interpreter_with_indexed_resource_drop() {
2560        let expr = r#"
2561           let user_id = "user";
2562           golem:it/api.{cart(user_id).drop}();
2563           "success"
2564        "#;
2565        let expr = Expr::from_text(expr).unwrap();
2566        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2567
2568        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2569
2570        let mut rib_interpreter = Interpreter::default();
2571        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
2572
2573        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
2574    }
2575
2576    #[test]
2577    async fn test_interpreter_with_indexed_resource_checkout() {
2578        let expr = r#"
2579           let user_id = "foo";
2580           let result = golem:it/api.{cart(user_id).checkout}();
2581           result
2582        "#;
2583
2584        let expr = Expr::from_text(expr).unwrap();
2585
2586        let result_type = variant(vec![
2587            case("error", str()),
2588            case("success", record(vec![field("order-id", str())])),
2589        ]);
2590
2591        let result_value = test_utils::get_value_and_type(
2592            &result_type,
2593            r#"
2594          success({order-id: "foo"})
2595        "#,
2596        );
2597
2598        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2599        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2600
2601        let mut rib_executor = test_utils::interpreter_static_response(&result_value, None);
2602        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2603
2604        assert_eq!(result.get_val().unwrap(), result_value);
2605    }
2606
2607    #[test]
2608    async fn test_interpreter_with_indexed_resource_get_cart_contents() {
2609        let expr = r#"
2610           let user_id = "bar";
2611           let result = golem:it/api.{cart(user_id).get-cart-contents}();
2612           result[0].product-id
2613        "#;
2614
2615        let expr = Expr::from_text(expr).unwrap();
2616
2617        let result_type = list(record(vec![
2618            field("product-id", str()),
2619            field("name", str()),
2620            field("price", f32()),
2621            field("quantity", u32()),
2622        ]));
2623
2624        let result_value = test_utils::get_value_and_type(
2625            &result_type,
2626            r#"
2627            [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}]
2628        "#,
2629        );
2630
2631        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2632        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2633
2634        let mut rib_executor = test_utils::interpreter_static_response(&result_value, None);
2635        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2636
2637        assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type());
2638    }
2639
2640    #[test]
2641    async fn test_interpreter_with_indexed_resource_update_item_quantity() {
2642        let expr = r#"
2643           let user_id = "jon";
2644           let product_id = "mac";
2645           let quantity = 1032;
2646           golem:it/api.{cart(user_id).update-item-quantity}(product_id, quantity);
2647           "successfully updated"
2648        "#;
2649        let expr = Expr::from_text(expr).unwrap();
2650
2651        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2652
2653        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2654
2655        let mut rib_executor = Interpreter::default();
2656
2657        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2658
2659        assert_eq!(
2660            result.get_val().unwrap(),
2661            "successfully updated".into_value_and_type()
2662        );
2663    }
2664
2665    #[test]
2666    async fn test_interpreter_with_indexed_resource_add_item() {
2667        let expr = r#"
2668           let user_id = "foo";
2669           let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 };
2670           golem:it/api.{cart(user_id).add-item}(product);
2671
2672           "successfully added"
2673        "#;
2674
2675        let expr = Expr::from_text(expr).unwrap();
2676
2677        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2678
2679        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2680
2681        let mut rib_executor = Interpreter::default();
2682
2683        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2684
2685        assert_eq!(
2686            result.get_val().unwrap(),
2687            "successfully added".into_value_and_type()
2688        );
2689    }
2690
2691    #[test]
2692    async fn test_interpreter_with_resource_add_item() {
2693        let expr = r#"
2694           let user_id = "foo";
2695           let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 };
2696           golem:it/api.{cart.add-item}(product);
2697
2698           "successfully added"
2699        "#;
2700
2701        let expr = Expr::from_text(expr).unwrap();
2702
2703        let component_metadata = test_utils::get_metadata_with_resource_without_params();
2704
2705        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2706
2707        let mut rib_executor = Interpreter::default();
2708
2709        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2710
2711        assert_eq!(
2712            result.get_val().unwrap(),
2713            "successfully added".into_value_and_type()
2714        );
2715    }
2716
2717    #[test]
2718    async fn test_interpreter_with_resource_get_cart_contents() {
2719        let expr = r#"
2720           let result = golem:it/api.{cart.get-cart-contents}();
2721           result[0].product-id
2722        "#;
2723
2724        let expr = Expr::from_text(expr).unwrap();
2725
2726        let result_type = list(record(vec![
2727            field("product-id", str()),
2728            field("name", str()),
2729            field("price", f32()),
2730            field("quantity", u32()),
2731        ]));
2732
2733        let result_value = test_utils::get_value_and_type(
2734            &result_type,
2735            r#"
2736            [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}]
2737        "#,
2738        );
2739
2740        let component_metadata = test_utils::get_metadata_with_resource_without_params();
2741        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2742
2743        let mut rib_executor = test_utils::interpreter_static_response(&result_value, None);
2744        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2745
2746        assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type());
2747    }
2748
2749    #[test]
2750    async fn test_interpreter_with_resource_update_item() {
2751        let expr = r#"
2752           let product_id = "mac";
2753           let quantity = 1032;
2754           golem:it/api.{cart.update-item-quantity}(product_id, quantity);
2755           "successfully updated"
2756        "#;
2757        let expr = Expr::from_text(expr).unwrap();
2758
2759        let component_metadata = test_utils::get_metadata_with_resource_without_params();
2760
2761        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2762
2763        let mut rib_executor = Interpreter::default();
2764
2765        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2766
2767        assert_eq!(
2768            result.get_val().unwrap(),
2769            "successfully updated".into_value_and_type()
2770        );
2771    }
2772
2773    #[test]
2774    async fn test_interpreter_with_resource_checkout() {
2775        let expr = r#"
2776           let result = golem:it/api.{cart.checkout}();
2777           result
2778        "#;
2779
2780        let expr = Expr::from_text(expr).unwrap();
2781
2782        let result_type = variant(vec![
2783            case("error", str()),
2784            case("success", record(vec![field("order-id", str())])),
2785        ]);
2786
2787        let result_value = test_utils::get_value_and_type(
2788            &result_type,
2789            r#"
2790          success({order-id: "foo"})
2791        "#,
2792        );
2793
2794        let component_metadata = test_utils::get_metadata_with_resource_without_params();
2795        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2796
2797        let mut rib_executor = test_utils::interpreter_static_response(&result_value, None);
2798        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2799
2800        assert_eq!(result.get_val().unwrap(), result_value);
2801    }
2802
2803    #[test]
2804    async fn test_interpreter_with_resource_drop() {
2805        let expr = r#"
2806           golem:it/api.{cart.drop}();
2807           "success"
2808        "#;
2809        let expr = Expr::from_text(expr).unwrap();
2810        let component_metadata = test_utils::get_metadata_with_resource_without_params();
2811
2812        let compiled = compiler::compile(expr, &component_metadata).unwrap();
2813
2814        let mut rib_interpreter = Interpreter::default();
2815        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
2816
2817        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
2818    }
2819
2820    #[test]
2821    async fn test_interpreter_for_select_index_expr_1() {
2822        // infinite computation will respond with an error - than a stack overflow
2823        // Note that, `list[1..]` is allowed while `for i in 1.. { yield i; }` is not
2824        let expr = r#"
2825              let list: list<u8> = [1, 2, 3, 4, 5];
2826              let index: u8 = 4;
2827              list[index]
2828              "#;
2829
2830        let expr = Expr::from_text(expr).unwrap();
2831
2832        let compiled = compiler::compile(expr, &vec![]).unwrap();
2833
2834        let mut interpreter = Interpreter::default();
2835        let result = interpreter.run(compiled.byte_code).await.unwrap();
2836
2837        let expected = ValueAndType::new(Value::U8(5), u8());
2838
2839        assert_eq!(result.get_val().unwrap(), expected);
2840    }
2841
2842    #[test]
2843    async fn test_interpreter_for_select_index_expr_out_of_bound() {
2844        let expr = r#"
2845              let list: list<u8> = [1, 2, 3, 4, 5];
2846              let index: u8 = 10;
2847              list[index]
2848              "#;
2849
2850        let expr = Expr::from_text(expr).unwrap();
2851
2852        let compiled = compiler::compile(expr, &vec![]).unwrap();
2853
2854        let mut interpreter = Interpreter::default();
2855        let result = interpreter.run(compiled.byte_code).await.unwrap_err();
2856
2857        assert_eq!(
2858            result,
2859            "index 10 is out of bound in the list of length 5".to_string()
2860        );
2861    }
2862
2863    #[test]
2864    async fn test_interpreter_for_select_index_expr_2() {
2865        let expr = r#"
2866              let list: list<u8> = [1, 2, 3, 4, 5];
2867              let indices: list<u8> = [0, 1, 2, 3];
2868
2869              for i in indices {
2870                 yield list[i];
2871              }
2872              "#;
2873
2874        let expr = Expr::from_text(expr).unwrap();
2875
2876        let compiled = compiler::compile(expr, &vec![]).unwrap();
2877
2878        let mut interpreter = Interpreter::default();
2879        let result = interpreter.run(compiled.byte_code).await.unwrap();
2880
2881        let expected = ValueAndType::new(
2882            Value::List(vec![Value::U8(1), Value::U8(2), Value::U8(3), Value::U8(4)]),
2883            list(u8()),
2884        );
2885
2886        assert_eq!(result.get_val().unwrap(), expected);
2887    }
2888
2889    #[test]
2890    async fn test_interpreter_for_select_index_expr_3() {
2891        let expr = r#"
2892              let list: list<u8> = [2, 5, 4];
2893              let indices: list<u8> = [0, 1];
2894
2895               reduce z, index in indices from 0u8 {
2896                  yield list[index] + z;
2897                }
2898              "#;
2899
2900        let expr = Expr::from_text(expr).unwrap();
2901
2902        let compiled = compiler::compile(expr, &vec![]).unwrap();
2903
2904        let mut interpreter = Interpreter::default();
2905        let result = interpreter.run(compiled.byte_code).await.unwrap();
2906
2907        let expected = ValueAndType::new(Value::U8(7), u8());
2908
2909        assert_eq!(result.get_val().unwrap(), expected);
2910    }
2911
2912    #[test]
2913    async fn test_interpreter_for_select_index_expr_4() {
2914        let expr = r#"
2915              let list: list<u8> = [2, 5, 4];
2916              let x: u8 = 0;
2917              let y: u8 = 2;
2918              list[x..=y]
2919              "#;
2920
2921        let expr = Expr::from_text(expr).unwrap();
2922
2923        let compiled = compiler::compile(expr, &vec![]).unwrap();
2924
2925        let mut interpreter = Interpreter::default();
2926        let result = interpreter.run(compiled.byte_code).await.unwrap();
2927
2928        let expected = ValueAndType::new(
2929            Value::List(vec![Value::U8(2), Value::U8(5), Value::U8(4)]),
2930            list(u8()),
2931        );
2932
2933        assert_eq!(result.get_val().unwrap(), expected);
2934    }
2935
2936    #[test]
2937    async fn test_interpreter_for_select_index_expr_5() {
2938        let expr = r#"
2939              let list: list<u8> = [2, 5, 4];
2940              let x: u8 = 0;
2941              let y: u8 = 2;
2942              let x1: u8 = 1;
2943              let result = list[x..=y];
2944              for i in result[x1..=y] {
2945                yield i;
2946              }
2947              "#;
2948
2949        let expr = Expr::from_text(expr).unwrap();
2950
2951        let compiled = compiler::compile(expr, &vec![]).unwrap();
2952
2953        let mut interpreter = Interpreter::default();
2954        let result = interpreter.run(compiled.byte_code).await.unwrap();
2955
2956        let expected = ValueAndType::new(Value::List(vec![Value::U8(5), Value::U8(4)]), list(u8()));
2957
2958        assert_eq!(result.get_val().unwrap(), expected);
2959    }
2960
2961    #[test]
2962    async fn test_interpreter_for_select_index_expr_6() {
2963        let expr = r#"
2964              let list: list<u8> = [2, 5, 4, 6];
2965              let x: u8 = 0;
2966              let y: u8 = 2;
2967              let result = list[x..y];
2968              for i in result[x..y] {
2969                yield i;
2970              }
2971              "#;
2972
2973        let expr = Expr::from_text(expr).unwrap();
2974
2975        let compiled = compiler::compile(expr, &vec![]).unwrap();
2976
2977        let mut interpreter = Interpreter::default();
2978        let result = interpreter.run(compiled.byte_code).await.unwrap();
2979
2980        let expected = ValueAndType::new(Value::List(vec![Value::U8(2), Value::U8(5)]), list(u8()));
2981
2982        assert_eq!(result.get_val().unwrap(), expected);
2983    }
2984
2985    #[test]
2986    async fn test_interpreter_for_select_index_expr_7() {
2987        let expr = r#"
2988              let list: list<u8> = [2, 5, 4, 6];
2989              let x: u8 = 0;
2990              let result = list[x..];
2991              for i in result[x..] {
2992                yield i;
2993              }
2994              "#;
2995
2996        let expr = Expr::from_text(expr).unwrap();
2997
2998        let compiled = compiler::compile(expr, &vec![]).unwrap();
2999
3000        let mut interpreter = Interpreter::default();
3001        let result = interpreter.run(compiled.byte_code).await.unwrap();
3002
3003        let expected = ValueAndType::new(Value::List(vec![Value::U8(2), Value::U8(5)]), list(u8()));
3004
3005        assert_eq!(result.get_val().unwrap(), expected);
3006    }
3007
3008    #[test]
3009    async fn test_interpreter_for_select_index_expr_8() {
3010        let expr = r#"
3011              let list: list<u8> = [2, 5, 4, 6];
3012              let result = list[0..2];
3013              for i in result[0..2] {
3014                yield i;
3015              }
3016              "#;
3017
3018        let expr = Expr::from_text(expr).unwrap();
3019
3020        let compiled = compiler::compile(expr, &vec![]).unwrap();
3021
3022        let mut interpreter = Interpreter::default();
3023        let result = interpreter.run(compiled.byte_code).await.unwrap();
3024
3025        let expected = ValueAndType::new(Value::List(vec![Value::U8(2), Value::U8(5)]), list(u8()));
3026
3027        assert_eq!(result.get_val().unwrap(), expected);
3028    }
3029
3030    // Simulating the behaviour in languages like rust
3031    // Emitting the description of the range than the evaluated range
3032    // Description given out as ValueAndType::Record
3033    #[test]
3034    async fn test_interpreter_range_returns_1() {
3035        let expr = r#"
3036              let x = 1..;
3037              x
3038              "#;
3039
3040        let expr = Expr::from_text(expr).unwrap();
3041
3042        let compiled = compiler::compile(expr, &vec![]).unwrap();
3043
3044        let mut interpreter = Interpreter::default();
3045        let result = interpreter.run(compiled.byte_code).await.unwrap();
3046
3047        let expected = ValueAndType::new(
3048            Value::Record(vec![
3049                Value::U64(1),
3050                Value::Bool(false), // non inclusive
3051            ]),
3052            record(vec![
3053                field("from", option(u64())),
3054                field("inclusive", bool()),
3055            ]),
3056        );
3057
3058        assert_eq!(result.get_val().unwrap(), expected);
3059    }
3060
3061    #[test]
3062    async fn test_interpreter_range_returns_2() {
3063        let expr = r#"
3064              let x = 1..2;
3065              x
3066              "#;
3067
3068        let expr = Expr::from_text(expr).unwrap();
3069
3070        let compiled = compiler::compile(expr, &vec![]).unwrap();
3071
3072        let mut interpreter = Interpreter::default();
3073        let result = interpreter.run(compiled.byte_code).await.unwrap();
3074
3075        let expected = ValueAndType::new(
3076            Value::Record(vec![
3077                Value::U64(1),
3078                Value::U64(2),
3079                Value::Bool(false), // non inclusive
3080            ]),
3081            record(vec![
3082                field("from", option(u64())),
3083                field("to", option(u64())),
3084                field("inclusive", bool()),
3085            ]),
3086        );
3087
3088        assert_eq!(result.get_val().unwrap(), expected);
3089    }
3090
3091    #[test]
3092    async fn test_interpreter_range_returns_3() {
3093        let expr = r#"
3094              let x = 1..=10;
3095              x
3096              "#;
3097
3098        let expr = Expr::from_text(expr).unwrap();
3099
3100        let compiled = compiler::compile(expr, &vec![]).unwrap();
3101
3102        let mut interpreter = Interpreter::default();
3103        let result = interpreter.run(compiled.byte_code).await.unwrap();
3104
3105        let expected = ValueAndType::new(
3106            Value::Record(vec![
3107                Value::U64(1),
3108                Value::U64(10),
3109                Value::Bool(true), // inclusive
3110            ]),
3111            record(vec![
3112                field("from", option(u64())),
3113                field("to", option(u64())),
3114                field("inclusive", bool()),
3115            ]),
3116        );
3117
3118        assert_eq!(result.get_val().unwrap(), expected);
3119    }
3120
3121    #[test]
3122    async fn test_interpreter_range_returns_4() {
3123        let expr = r#"
3124              let x = 1:u64;
3125              let y = x;
3126              let range = x..=y;
3127              let range2 = x..;
3128              let range3 = x..y;
3129              range;
3130              range2;
3131              range3
3132              "#;
3133
3134        let expr = Expr::from_text(expr).unwrap();
3135
3136        let compiled = compiler::compile(expr, &vec![]).unwrap();
3137
3138        let mut interpreter = Interpreter::default();
3139        let result = interpreter.run(compiled.byte_code).await.unwrap();
3140
3141        let expected = ValueAndType::new(
3142            Value::Record(vec![Value::U64(1), Value::U64(1), Value::Bool(false)]),
3143            record(vec![
3144                field("from", option(u64())),
3145                field("to", option(u64())),
3146                field("inclusive", bool()),
3147            ]),
3148        );
3149
3150        assert_eq!(result.get_val().unwrap(), expected);
3151    }
3152
3153    #[test]
3154    async fn test_interpreter_range_returns_5() {
3155        let expr = r#"
3156              let y = 1:u64 + 10: u64;
3157              1..y
3158              "#;
3159
3160        let expr = Expr::from_text(expr).unwrap();
3161
3162        let compiled = compiler::compile(expr, &vec![]).unwrap();
3163
3164        let mut interpreter = Interpreter::default();
3165        let result = interpreter.run(compiled.byte_code).await.unwrap();
3166
3167        let expected = ValueAndType::new(
3168            Value::Record(vec![Value::U64(1), Value::U64(11), Value::Bool(false)]),
3169            record(vec![
3170                field("from", option(u64())),
3171                field("to", option(u64())),
3172                field("inclusive", bool()),
3173            ]),
3174        );
3175
3176        assert_eq!(result.get_val().unwrap(), expected);
3177    }
3178
3179    #[test]
3180    async fn test_interpreter_range_with_comprehension_1() {
3181        let expr = r#"
3182              let range = 1..=5;
3183              for i in range {
3184                yield i;
3185              }
3186
3187              "#;
3188
3189        let expr = Expr::from_text(expr).unwrap();
3190
3191        let compiled = compiler::compile(expr, &vec![]).unwrap();
3192
3193        let mut interpreter = Interpreter::default();
3194        let result = interpreter.run(compiled.byte_code).await.unwrap();
3195
3196        let expected = ValueAndType::new(
3197            Value::List(vec![
3198                Value::U64(1),
3199                Value::U64(2),
3200                Value::U64(3),
3201                Value::U64(4),
3202                Value::U64(5),
3203            ]),
3204            list(u64()),
3205        );
3206
3207        assert_eq!(result.get_val().unwrap(), expected);
3208    }
3209
3210    #[test]
3211    async fn test_interpreter_range_with_comprehension_2() {
3212        let expr = r#"
3213              let range = 1..5;
3214              for i in range {
3215                yield i;
3216              }
3217
3218              "#;
3219
3220        let expr = Expr::from_text(expr).unwrap();
3221
3222        let compiled = compiler::compile(expr, &vec![]).unwrap();
3223
3224        let mut interpreter = Interpreter::default();
3225        let result = interpreter.run(compiled.byte_code).await.unwrap();
3226
3227        let expected = ValueAndType::new(
3228            Value::List(vec![
3229                Value::U64(1),
3230                Value::U64(2),
3231                Value::U64(3),
3232                Value::U64(4),
3233            ]),
3234            list(u64()),
3235        );
3236
3237        assert_eq!(result.get_val().unwrap(), expected);
3238    }
3239
3240    #[test]
3241    async fn test_interpreter_range_with_comprehension_3() {
3242        // infinite computation will respond with an error - than a stack overflow
3243        // Note that, `list[1..]` is allowed while `for i in 1.. { yield i; }` is not
3244        let expr = r#"
3245              let range = 1:u64..;
3246              for i in range {
3247                yield i;
3248              }
3249
3250              "#;
3251
3252        let expr = Expr::from_text(expr).unwrap();
3253
3254        let compiled = compiler::compile(expr, &vec![]).unwrap();
3255
3256        let mut interpreter = Interpreter::default();
3257        let result = interpreter.run(compiled.byte_code).await;
3258        assert!(result.is_err());
3259    }
3260
3261    #[test]
3262    async fn test_interpreter_range_with_list_reduce_1() {
3263        // infinite computation will respond with an error - than a stack overflow
3264        // Note that, `list[1..]` is allowed while `for i in 1.. { yield i; }` is not
3265        let expr = r#"
3266                let initial: u8 = 1;
3267                let final: u8 = 5;
3268                let x = initial..final;
3269
3270                reduce z, a in x from 0u8 {
3271                  yield z + a;
3272                }
3273
3274              "#;
3275
3276        let expr = Expr::from_text(expr).unwrap();
3277
3278        let compiled = compiler::compile(expr, &vec![]).unwrap();
3279
3280        let mut interpreter = Interpreter::default();
3281        let result = interpreter.run(compiled.byte_code).await.unwrap();
3282
3283        let expected = ValueAndType::new(Value::U8(10), u8());
3284
3285        assert_eq!(result.get_val().unwrap(), expected);
3286    }
3287
3288    #[test]
3289    async fn test_interpreter_ephemeral_worker_0() {
3290        let expr = r#"
3291              let x = instance();
3292              let result = x.foo("bar");
3293              result
3294            "#;
3295        let expr = Expr::from_text(expr).unwrap();
3296
3297        let component_metadata = test_utils::get_metadata();
3298
3299        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3300
3301        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3302
3303        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3304
3305        let expected_val = test_utils::parse_function_details(
3306            r#"
3307              {
3308                 worker-name: none,
3309                 function-name: "amazon:shopping-cart/api1.{foo}",
3310                 args0: "bar"
3311              }
3312            "#,
3313        );
3314
3315        assert_eq!(result.get_val().unwrap(), expected_val);
3316    }
3317
3318    #[test]
3319    async fn test_interpreter_ephemeral_worker_1() {
3320        let expr = r#"
3321              let x = instance();
3322              x
3323            "#;
3324        let expr = Expr::from_text(expr).unwrap();
3325
3326        let component_metadata = test_utils::get_metadata();
3327
3328        let compiled = compiler::compile(expr, &component_metadata);
3329
3330        assert!(compiled.is_err());
3331    }
3332
3333    #[test]
3334    async fn test_interpreter_ephemeral_worker_2() {
3335        let expr = r#"
3336             instance
3337            "#;
3338        let expr = Expr::from_text(expr).unwrap();
3339
3340        let component_metadata = test_utils::get_metadata();
3341
3342        let compiled = compiler::compile(expr, &component_metadata);
3343
3344        assert!(compiled.is_err());
3345    }
3346
3347    #[test]
3348    async fn test_interpreter_ephemeral_worker_3() {
3349        let expr = r#"
3350              instance()
3351            "#;
3352        let expr = Expr::from_text(expr).unwrap();
3353
3354        let component_metadata = test_utils::get_metadata();
3355
3356        let compiled = compiler::compile(expr, &component_metadata);
3357
3358        assert!(compiled.is_err());
3359    }
3360
3361    #[test]
3362    async fn test_interpreter_ephemeral_worker_4() {
3363        let expr = r#"
3364              instance().foo("bar")
3365            "#;
3366        let expr = Expr::from_text(expr).unwrap();
3367
3368        let component_metadata = test_utils::get_metadata();
3369
3370        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3371
3372        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3373
3374        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3375
3376        let expected_val = test_utils::parse_function_details(
3377            r#"
3378              {
3379                 worker-name: none,
3380                 function-name: "amazon:shopping-cart/api1.{foo}",
3381                 args0: "bar"
3382              }
3383            "#,
3384        );
3385
3386        assert_eq!(result.get_val().unwrap(), expected_val);
3387    }
3388
3389    #[test]
3390    async fn test_interpreter_ephemeral_worker_5() {
3391        let expr = r#"
3392              let result = instance.foo("bar");
3393              result
3394            "#;
3395        let expr = Expr::from_text(expr).unwrap();
3396        let component_metadata = test_utils::get_metadata();
3397
3398        let compiled = compiler::compile(expr, &component_metadata)
3399            .unwrap_err()
3400            .to_string();
3401
3402        assert_eq!(compiled, "error in the following rib found at line 2, column 28\n`instance`\ncause: `instance` is a reserved keyword\nhelp: use `instance()` instead of `instance` to create an ephemeral worker instance.\nhelp: for a durable worker, use `instance(\"foo\")` where `\"foo\"` is the worker name\n".to_string());
3403    }
3404
3405    #[test]
3406    async fn test_interpreter_ephemeral_worker_6() {
3407        let expr = r#"
3408                let x = instance();
3409                let result = x.bar("bar");
3410                result
3411            "#;
3412        let expr = Expr::from_text(expr).unwrap();
3413        let component_metadata = test_utils::get_metadata();
3414
3415        let compilation_error = compiler::compile(expr, &component_metadata)
3416            .unwrap_err()
3417            .to_string();
3418
3419        assert_eq!(
3420            compilation_error,
3421            "error in the following rib found at line 3, column 30\n`x.bar(\"bar\")`\ncause: invalid function call `bar`\nmultiple interfaces contain function 'bar'. specify an interface name as type parameter from: api1, api2\n".to_string()
3422        );
3423    }
3424
3425    #[test]
3426    async fn test_interpreter_ephemeral_worker_7() {
3427        let expr = r#"
3428                let worker = instance();
3429                let invokes: list<u8> = [1, 2, 3, 4];
3430
3431                for i in invokes {
3432                    yield worker.qux[wasi:clocks]("bar");
3433                };
3434
3435                "success"
3436            "#;
3437        let expr = Expr::from_text(expr).unwrap();
3438        let component_metadata = test_utils::get_metadata();
3439
3440        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3441
3442        let mut rib_interpreter =
3443            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3444
3445        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3446
3447        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3448    }
3449
3450    /// Durable worker
3451    #[test]
3452    async fn test_interpreter_durable_worker_0() {
3453        let expr = r#"
3454                let worker = instance("my-worker");
3455                let result = worker.foo("bar");
3456                result
3457            "#;
3458        let expr = Expr::from_text(expr).unwrap();
3459        let component_metadata = test_utils::get_metadata();
3460
3461        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3462
3463        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3464
3465        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3466
3467        let expected_val = test_utils::parse_function_details(
3468            r#"
3469              {
3470                 worker-name: some("my-worker"),
3471                 function-name: "amazon:shopping-cart/api1.{foo}",
3472                 args0: "bar"
3473              }
3474            "#,
3475        );
3476
3477        assert_eq!(result.get_val().unwrap(), expected_val);
3478    }
3479
3480    #[test]
3481    async fn test_interpreter_durable_worker_1() {
3482        let expr = r#"
3483                instance("my-worker").foo("bar")
3484            "#;
3485        let expr = Expr::from_text(expr).unwrap();
3486        let component_metadata = test_utils::get_metadata();
3487
3488        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3489
3490        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3491
3492        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3493
3494        let expected_val = test_utils::parse_function_details(
3495            r#"
3496              {
3497                 worker-name: some("my-worker"),
3498                 function-name: "amazon:shopping-cart/api1.{foo}",
3499                 args0: "bar"
3500              }
3501            "#,
3502        );
3503
3504        assert_eq!(result.get_val().unwrap(), expected_val);
3505    }
3506
3507    #[test]
3508    async fn test_interpreter_durable_worker_2() {
3509        let expr = r#"
3510                let result = instance("my-worker").foo("bar");
3511                result
3512            "#;
3513        let expr = Expr::from_text(expr).unwrap();
3514        let component_metadata = test_utils::get_metadata();
3515
3516        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3517
3518        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3519
3520        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3521
3522        let expected_val = test_utils::parse_function_details(
3523            r#"
3524              {
3525                 worker-name: some("my-worker"),
3526                 function-name: "amazon:shopping-cart/api1.{foo}",
3527                 args0: "bar"
3528              }
3529            "#,
3530        );
3531
3532        assert_eq!(result.get_val().unwrap(), expected_val);
3533    }
3534
3535    #[test]
3536    async fn test_interpreter_durable_worker_3() {
3537        let expr = r#"
3538                let my_worker = instance("my-worker");
3539                let result = my_worker.foo[api1]("bar");
3540                result
3541            "#;
3542        let expr = Expr::from_text(expr).unwrap();
3543        let component_metadata = test_utils::get_metadata();
3544
3545        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3546
3547        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3548
3549        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3550
3551        let expected_val = test_utils::parse_function_details(
3552            r#"
3553              {
3554                 worker-name: some("my-worker"),
3555                 function-name: "amazon:shopping-cart/api1.{foo}",
3556                 args0: "bar"
3557              }
3558            "#,
3559        );
3560
3561        assert_eq!(result.get_val().unwrap(), expected_val);
3562    }
3563
3564    #[test]
3565    async fn test_interpreter_durable_worker_4() {
3566        let expr = r#"
3567                let worker = instance("my-worker");
3568                let result = worker.bar("bar");
3569                result
3570            "#;
3571        let expr = Expr::from_text(expr).unwrap();
3572        let component_metadata = test_utils::get_metadata();
3573
3574        let compilation_error = compiler::compile(expr, &component_metadata)
3575            .unwrap_err()
3576            .to_string();
3577
3578        assert_eq!(
3579            compilation_error,
3580            "error in the following rib found at line 3, column 30\n`worker.bar(\"bar\")`\ncause: invalid function call `bar`\nmultiple interfaces contain function 'bar'. specify an interface name as type parameter from: api1, api2\n".to_string()
3581        );
3582    }
3583
3584    #[test]
3585    async fn test_interpreter_durable_worker_5() {
3586        let expr = r#"
3587                let worker = instance("my-worker");
3588                let result = worker.bar[api1]("bar");
3589                result
3590            "#;
3591        let expr = Expr::from_text(expr).unwrap();
3592        let component_metadata = test_utils::get_metadata();
3593
3594        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3595
3596        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3597
3598        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3599
3600        let expected_val = test_utils::parse_function_details(
3601            r#"
3602              {
3603                 worker-name: some("my-worker"),
3604                 function-name: "amazon:shopping-cart/api1.{bar}",
3605                 args0: "bar"
3606              }
3607            "#,
3608        );
3609
3610        assert_eq!(result.get_val().unwrap(), expected_val);
3611    }
3612
3613    #[test]
3614    async fn test_interpreter_durable_worker_6() {
3615        let expr = r#"
3616                let worker = instance("my-worker");
3617                let result = worker.bar[api2]("bar");
3618                result
3619            "#;
3620        let expr = Expr::from_text(expr).unwrap();
3621        let component_metadata = test_utils::get_metadata();
3622
3623        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3624
3625        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3626
3627        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3628
3629        let expected_val = test_utils::parse_function_details(
3630            r#"
3631              {
3632                 worker-name: some("my-worker"),
3633                 function-name: "amazon:shopping-cart/api2.{bar}",
3634                 args0: "bar"
3635              }
3636            "#,
3637        );
3638
3639        assert_eq!(result.get_val().unwrap(), expected_val);
3640    }
3641
3642    #[test]
3643    async fn test_interpreter_durable_worker_7() {
3644        let expr = r#"
3645                let worker = instance("my-worker");
3646                let result = worker.baz("bar");
3647                result
3648            "#;
3649        let expr = Expr::from_text(expr).unwrap();
3650        let component_metadata = test_utils::get_metadata();
3651
3652        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3653
3654        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3655
3656        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3657
3658        let expected_val = test_utils::parse_function_details(
3659            r#"
3660              {
3661                 worker-name: some("my-worker"),
3662                 function-name: "wasi:clocks/monotonic-clock.{baz}",
3663                 args0: "bar"
3664              }
3665            "#,
3666        );
3667
3668        assert_eq!(result.get_val().unwrap(), expected_val);
3669    }
3670
3671    #[test]
3672    async fn test_interpreter_durable_worker_8() {
3673        let expr = r#"
3674                let worker = instance("my-worker");
3675                let result = worker.qux("bar");
3676                result
3677            "#;
3678        let expr = Expr::from_text(expr).unwrap();
3679        let component_metadata = test_utils::get_metadata();
3680
3681        let compiled = compiler::compile(expr, &component_metadata)
3682            .unwrap_err()
3683            .to_string();
3684
3685        assert_eq!(
3686            compiled,
3687            "error in the following rib found at line 3, column 30\n`worker.qux(\"bar\")`\ncause: invalid function call `qux`\nfunction 'qux' exists in multiple packages. specify a package name as type parameter from: amazon:shopping-cart (interfaces: api1), wasi:clocks (interfaces: monotonic-clock)\n".to_string()
3688        );
3689    }
3690
3691    #[test]
3692    async fn test_interpreter_durable_worker_9() {
3693        let expr = r#"
3694                let worker = instance("my-worker");
3695                let result = worker.qux[amazon:shopping-cart]("bar");
3696                result
3697            "#;
3698        let expr = Expr::from_text(expr).unwrap();
3699        let component_metadata = test_utils::get_metadata();
3700
3701        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3702
3703        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3704
3705        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3706
3707        let expected_val = test_utils::parse_function_details(
3708            r#"
3709              {
3710                 worker-name: some("my-worker"),
3711                 function-name: "amazon:shopping-cart/api1.{qux}",
3712                 args0: "bar"
3713              }
3714            "#,
3715        );
3716
3717        assert_eq!(result.get_val().unwrap(), expected_val);
3718    }
3719
3720    #[test]
3721    async fn test_interpreter_durable_worker_10() {
3722        let expr = r#"
3723                let worker = instance("my-worker");
3724                let result = worker.qux[wasi:clocks]("bar");
3725                result
3726            "#;
3727        let expr = Expr::from_text(expr).unwrap();
3728        let component_metadata = test_utils::get_metadata();
3729
3730        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3731
3732        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3733
3734        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3735
3736        let expected_val = test_utils::parse_function_details(
3737            r#"
3738              {
3739                 worker-name: some("my-worker"),
3740                 function-name: "wasi:clocks/monotonic-clock.{qux}",
3741                 args0: "bar"
3742              }
3743            "#,
3744        );
3745
3746        assert_eq!(result.get_val().unwrap(), expected_val);
3747    }
3748
3749    #[test]
3750    async fn test_interpreter_durable_worker_11() {
3751        let expr = r#"
3752                let worker = instance("my-worker");
3753                let invokes: list<u8> = [1, 2, 3, 4];
3754
3755                for i in invokes {
3756                    yield worker.qux[wasi:clocks]("bar");
3757                };
3758
3759                "success"
3760            "#;
3761        let expr = Expr::from_text(expr).unwrap();
3762        let component_metadata = test_utils::get_metadata();
3763
3764        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3765
3766        let mut rib_interpreter =
3767            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3768
3769        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3770
3771        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3772    }
3773
3774    #[test]
3775    async fn test_interpreter_durable_worker_with_resource_0() {
3776        let expr = r#"
3777                let worker = instance("my-worker");
3778                worker.cart[golem:it]("bar")
3779            "#;
3780        let expr = Expr::from_text(expr).unwrap();
3781        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3782
3783        let compiled = compiler::compile(expr, &component_metadata)
3784            .unwrap_err()
3785            .to_string();
3786
3787        let expected = r#"
3788            error in the following rib found at line 3, column 17
3789            `cart("bar")`
3790            cause: program is invalid as it returns a resource constructor
3791            "#;
3792
3793        assert_eq!(compiled, strip_spaces(expected));
3794    }
3795
3796    // This resource construction is a Noop, and compiler can give warnings
3797    // once we support warnings in the compiler
3798    #[test]
3799    async fn test_interpreter_durable_worker_with_resource_1() {
3800        let expr = r#"
3801                let worker = instance("my-worker");
3802                worker.cart[golem:it]("bar");
3803                "success"
3804            "#;
3805        let expr = Expr::from_text(expr).unwrap();
3806        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3807
3808        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3809
3810        let mut rib_interpreter =
3811            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3812
3813        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3814
3815        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3816    }
3817
3818    #[test]
3819    async fn test_interpreter_durable_worker_with_resource_2() {
3820        let expr = r#"
3821                let worker = instance("my-worker");
3822                let cart = worker.cart[golem:it]("bar");
3823                let result = cart.add-item({product-id: "mac", name: "macbook", quantity: 1:u32, price: 1:f32});
3824                result
3825            "#;
3826        let expr = Expr::from_text(expr).unwrap();
3827        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3828
3829        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3830
3831        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
3832
3833        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3834
3835        let analysed_type = record(vec![
3836            field("worker-name", option(str())),
3837            field("function-name", str()),
3838            field(
3839                "args0",
3840                record(vec![
3841                    field("product-id", str()),
3842                    field("name", str()),
3843                    field("price", f32()),
3844                    field("quantity", u32()),
3845                ]),
3846            ),
3847        ]);
3848
3849        let expected_val = get_value_and_type(
3850            &analysed_type,
3851            r#"
3852              {
3853                 worker-name: some("my-worker"),
3854                 function-name: "golem:it/api.{cart(\"bar\").add-item}",
3855                 args0: {product-id: "mac", name: "macbook", price: 1.0, quantity: 1}
3856              }
3857            "#,
3858        );
3859
3860        assert_eq!(result.get_val().unwrap(), expected_val);
3861    }
3862
3863    #[test]
3864    async fn test_interpreter_durable_worker_with_resource_3() {
3865        let expr = r#"
3866                let worker = instance("my-worker");
3867                let cart = worker.cart[golem:it]("bar");
3868                cart.add-items({product-id: "mac", name: "macbook", quantity: 1:u32, price: 1:f32});
3869                "success"
3870            "#;
3871        let expr = Expr::from_text(expr).unwrap();
3872        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3873
3874        let compiled = compiler::compile(expr, &component_metadata)
3875            .unwrap_err()
3876            .to_string();
3877
3878        assert_eq!(compiled, "error in the following rib found at line 4, column 17\n`cart.add-items({product-id: \"mac\", name: \"macbook\", quantity: 1: u32, price: 1: f32})`\ncause: invalid function call `add-items`\nfunction 'add-items' not found\n".to_string());
3879    }
3880
3881    #[test]
3882    async fn test_interpreter_durable_worker_with_resource_4() {
3883        let expr = r#"
3884                let worker = instance("my-worker");
3885                let cart = worker.carts[golem:it]("bar");
3886                cart.add-item({product-id: "mac", name: "macbook", quantity: 1:u32, price: 1:f32});
3887                "success"
3888            "#;
3889        let expr = Expr::from_text(expr).unwrap();
3890        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3891
3892        let compiled = compiler::compile(expr, &component_metadata)
3893            .unwrap_err()
3894            .to_string();
3895
3896        assert_eq!(
3897            compiled,
3898            "error in the following rib found at line 3, column 28\n`worker.carts[golem:it](\"bar\")`\ncause: invalid function call `carts`\nfunction 'carts' not found in package 'golem:it'\n".to_string()
3899        );
3900    }
3901
3902    #[test]
3903    async fn test_interpreter_durable_worker_with_resource_5() {
3904        // Ephemeral
3905        let expr = r#"
3906                let worker = instance();
3907                let cart = worker.cart[golem:it]("bar");
3908                cart.add-item({product-id: "mac", name: "macbook", quantity: 1, price: 1});
3909                "success"
3910            "#;
3911        let expr = Expr::from_text(expr).unwrap();
3912        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3913
3914        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3915
3916        let mut rib_interpreter =
3917            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3918
3919        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3920
3921        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3922    }
3923
3924    #[test]
3925    async fn test_interpreter_durable_worker_with_resource_6() {
3926        // Ephemeral
3927        let expr = r#"
3928                let worker = instance();
3929                let cart = worker.cart[golem:it]("bar");
3930                cart.add-item({product-id: "mac", name: 1, quantity: 1, price: 1});
3931                "success"
3932            "#;
3933        let expr = Expr::from_text(expr).unwrap();
3934        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3935
3936        let error_message = compiler::compile(expr, &component_metadata)
3937            .unwrap_err()
3938            .to_string();
3939
3940        let expected = r#"
3941            error in the following rib found at line 4, column 31
3942            `{product-id: "mac", name: 1, quantity: 1, price: 1}`
3943            found within:
3944            `golem:it/api.{cart("bar").add-item}({product-id: "mac", name: 1, quantity: 1, price: 1})`
3945            cause: type mismatch at path: `name`. expected string
3946            invalid argument to the function `golem:it/api.{cart("bar").add-item}`
3947            "#;
3948
3949        assert_eq!(error_message, strip_spaces(expected));
3950    }
3951
3952    #[test]
3953    async fn test_interpreter_durable_worker_with_resource_7() {
3954        let expr = r#"
3955                let worker = instance("my-worker");
3956                let cart = worker.cart("bar");
3957                cart.add-item({product-id: "mac", name: "apple", price: 1, quantity: 1});
3958                "success"
3959            "#;
3960        let expr = Expr::from_text(expr).unwrap();
3961        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3962
3963        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3964
3965        let mut rib_interpreter =
3966            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3967
3968        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3969
3970        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3971    }
3972
3973    #[test]
3974    async fn test_interpreter_durable_worker_with_resource_8() {
3975        let expr = r#"
3976                let worker = instance("my-worker");
3977                let a = "mac";
3978                let b = "apple";
3979                let c = 1;
3980                let d = 1;
3981                let cart = worker.cart("bar");
3982                cart.add-item({product-id: a, name: b, quantity: c, price: d});
3983                "success"
3984            "#;
3985        let expr = Expr::from_text(expr).unwrap();
3986        let component_metadata = test_utils::get_metadata_with_resource_with_params();
3987
3988        let compiled = compiler::compile(expr, &component_metadata).unwrap();
3989
3990        let mut rib_interpreter =
3991            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
3992
3993        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3994
3995        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3996    }
3997
3998    #[test]
3999    async fn test_interpreter_durable_worker_with_resource_9() {
4000        let expr = r#"
4001                let worker = instance("my-worker");
4002                let a = "mac";
4003                let b = "apple";
4004                let c = 1;
4005                let d = 1;
4006                let cart = worker.cart("bar");
4007                cart.add-item({product-id: a, name: b, quantity: c, price: d});
4008                cart.remove-item(a);
4009                cart.update-item-quantity(a, 2);
4010                let result = cart.get-cart-contents();
4011                cart.drop();
4012                result
4013            "#;
4014        let expr = Expr::from_text(expr).unwrap();
4015        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4016
4017        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4018
4019        let mut rib_interpreter =
4020            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
4021
4022        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4023
4024        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4025    }
4026
4027    #[test]
4028    async fn test_interpreter_durable_worker_with_resource_10() {
4029        let expr = r#"
4030                let my_worker = "my-worker";
4031                let worker = instance(my_worker);
4032                let a = "mac";
4033                let b = "apple";
4034                let c = 1;
4035                let d = 1;
4036                let cart = worker.cart("bar");
4037                cart.add-item({product-id: a, name: b, price: d, quantity: c});
4038                cart.remove-item(a);
4039                cart.update-item-quantity(a, 2);
4040                let result = cart.get-cart-contents();
4041                cart.drop();
4042                result
4043            "#;
4044        let expr = Expr::from_text(expr).unwrap();
4045        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4046
4047        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4048
4049        let mut rib_interpreter =
4050            test_utils::interpreter_static_response(&"success".into_value_and_type(), None);
4051
4052        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4053
4054        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4055    }
4056
4057    #[test]
4058    async fn test_interpreter_durable_worker_with_resource_11() {
4059        let expr = r#"
4060                let worker = instance(request.path.user-id: string);
4061                let result = worker.qux[amazon:shopping-cart]("bar");
4062                result
4063            "#;
4064        let expr = Expr::from_text(expr).unwrap();
4065        let component_metadata = test_utils::get_metadata();
4066
4067        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4068
4069        let mut input = HashMap::new();
4070
4071        // Passing request data as input to interpreter
4072        let rib_input_key = "request";
4073        let rib_input_value = ValueAndType::new(
4074            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
4075            record(vec![field("path", record(vec![field("user-id", str())]))]),
4076        );
4077
4078        input.insert(rib_input_key.to_string(), rib_input_value);
4079
4080        let rib_input = RibInput::new(input);
4081
4082        let mut rib_interpreter = test_utils::interpreter_static_response(
4083            &"success".into_value_and_type(),
4084            Some(rib_input),
4085        );
4086
4087        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4088
4089        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4090    }
4091
4092    #[test]
4093    async fn test_interpreter_durable_worker_with_resource_12() {
4094        let expr = r#"
4095                let user_id1: string = request.path.user-id;
4096                let user_id2: string = request.path.user-id;
4097                let worker1 = instance(user_id1);
4098                let result1 = worker1.qux[amazon:shopping-cart]("bar");
4099                let worker2 = instance(user_id2);
4100                let result2 = worker2.qux[amazon:shopping-cart]("bar");
4101                user_id2
4102            "#;
4103        let expr = Expr::from_text(expr).unwrap();
4104        let component_metadata = test_utils::get_metadata();
4105
4106        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4107
4108        let mut input = HashMap::new();
4109
4110        let rib_input_key = "request";
4111        let rib_input_value = ValueAndType::new(
4112            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
4113            record(vec![field("path", record(vec![field("user-id", str())]))]),
4114        );
4115
4116        input.insert(rib_input_key.to_string(), rib_input_value);
4117
4118        let rib_input = RibInput::new(input);
4119
4120        let mut rib_interpreter = test_utils::interpreter_static_response(
4121            &"success".into_value_and_type(),
4122            Some(rib_input),
4123        );
4124
4125        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4126
4127        assert_eq!(result.get_val().unwrap(), "user".into_value_and_type());
4128    }
4129
4130    #[test]
4131    async fn test_interpreter_durable_worker_with_resource_13() {
4132        let expr = r#"
4133                let worker1 = instance("foo");
4134                let result = worker.qux[amazon:shopping-cart]("bar");
4135                "success"
4136            "#;
4137        let expr = Expr::from_text(expr).unwrap();
4138        let component_metadata = test_utils::get_metadata();
4139
4140        let error = compiler::compile(expr, &component_metadata)
4141            .unwrap_err()
4142            .to_string();
4143
4144        assert_eq!(error, "error in the following rib found at line 3, column 30\n`worker.qux[amazon:shopping-cart](\"bar\")`\ncause: invalid method invocation `worker.qux`. make sure `worker` is defined and is a valid instance type (i.e, resource or worker)\n");
4145    }
4146
4147    #[test]
4148    async fn test_interpreter_durable_worker_with_resource_14() {
4149        let expr = r#"
4150                let worker = instance(1: u32);
4151                let result = worker.qux[amazon:shopping-cart]("bar");
4152                "success"
4153            "#;
4154        let expr = Expr::from_text(expr).unwrap();
4155        let component_metadata = test_utils::get_metadata();
4156
4157        let error = compiler::compile(expr, &component_metadata)
4158            .unwrap_err()
4159            .to_string();
4160
4161        let expected = r#"
4162            error in the following rib found at line 2, column 39
4163            `1: u32`
4164            cause: expected string, found u32
4165            "#;
4166
4167        assert_eq!(error, strip_spaces(expected));
4168    }
4169
4170    #[test]
4171    async fn test_interpreter_durable_worker_with_resource_15() {
4172        let expr = r#"
4173                let worker = instance("my-worker-name");
4174                let result = worker.qux[amazon:shopping-cart]("param1");
4175                result
4176            "#;
4177        let expr = Expr::from_text(expr).unwrap();
4178        let component_metadata = test_utils::get_metadata();
4179
4180        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4181
4182        let mut rib_interpreter = test_utils::interpreter_worker_details_response(None);
4183
4184        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4185
4186        let result_val = result.get_val().unwrap();
4187
4188        let expected_val = test_utils::parse_function_details(
4189            r#"
4190              {
4191                 worker-name: some("my-worker-name"),
4192                 function-name: "amazon:shopping-cart/api1.{qux}",
4193                 args0: "param1"
4194              }
4195            "#,
4196        );
4197
4198        assert_eq!(result_val, expected_val);
4199    }
4200
4201    #[test]
4202    async fn test_interpreter_durable_worker_with_resource_16() {
4203        let expr = r#"
4204                let x = request.path.user-id;
4205                let worker = instance(x);
4206                let cart = worker.cart("bar");
4207                let result = cart.get-cart-contents();
4208                result
4209            "#;
4210        let expr = Expr::from_text(expr).unwrap();
4211        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4212
4213        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4214
4215        let mut input = HashMap::new();
4216
4217        let rib_input_key = "request";
4218        let rib_input_value = ValueAndType::new(
4219            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
4220            record(vec![field("path", record(vec![field("user-id", str())]))]),
4221        );
4222
4223        input.insert(rib_input_key.to_string(), rib_input_value);
4224
4225        let rib_input = RibInput::new(input);
4226
4227        let mut rib_interpreter = test_utils::interpreter_worker_details_response(Some(rib_input));
4228
4229        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4230
4231        let result_val = result.get_val().unwrap();
4232
4233        let expected_analysed_type = record(vec![
4234            field("worker-name", option(str())),
4235            field("function-name", str()),
4236        ]);
4237
4238        let expected_val = parse_value_and_type(
4239            &expected_analysed_type,
4240            r#"
4241              {
4242                 worker-name: some("user"),
4243                 function-name: "golem:it/api.{cart(\"bar\").get-cart-contents}",
4244              }
4245            "#,
4246        )
4247        .unwrap();
4248
4249        assert_eq!(result_val, expected_val)
4250    }
4251
4252    #[test]
4253    async fn test_interpreter_durable_worker_with_resource_17() {
4254        let expr = r#"
4255                let x: string = request.path.user-id;
4256                let min: u8 = 1;
4257                let max: u8 = 3;
4258                let result = for i in min..=max {
4259                   let worker = instance("my-worker");
4260                   let cart = worker.cart("bar");
4261                   yield cart.get-cart-contents();
4262                };
4263                result
4264            "#;
4265        let expr = Expr::from_text(expr).unwrap();
4266        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4267
4268        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4269
4270        let mut input = HashMap::new();
4271
4272        let rib_input_key = "request";
4273        let rib_input_value = ValueAndType::new(
4274            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
4275            record(vec![field("path", record(vec![field("user-id", str())]))]),
4276        );
4277
4278        input.insert(rib_input_key.to_string(), rib_input_value);
4279
4280        let rib_input = RibInput::new(input);
4281
4282        let mut rib_interpreter = test_utils::interpreter_worker_details_response(Some(rib_input));
4283
4284        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4285
4286        let result_val = result.get_val().unwrap().value;
4287
4288        let worker_name = Some("my-worker".to_string()).into_value();
4289        let function_name = "golem:it/api.{cart(\"bar\").get-cart-contents}"
4290            .to_string()
4291            .into_value();
4292
4293        let expected = Value::List(vec![
4294            Value::Record(vec![worker_name.clone(), function_name.clone()]),
4295            Value::Record(vec![worker_name.clone(), function_name.clone()]),
4296            Value::Record(vec![worker_name.clone(), function_name.clone()]),
4297        ]);
4298
4299        assert_eq!(result_val, expected);
4300    }
4301
4302    #[test]
4303    async fn test_interpreter_durable_worker_with_resource_18() {
4304        let expr = r#"
4305
4306            let initial = 1: u64;
4307            let final = 5: u64;
4308            let range = initial..final;
4309            let worker = instance("my-worker");
4310            let cart = worker.cart[golem:it]("bar");
4311
4312            for i in range {
4313                yield cart.add-item(request.body);
4314            };
4315
4316            "success"
4317        "#;
4318        let expr = Expr::from_text(expr).unwrap();
4319        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4320
4321        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4322
4323        let mut input = HashMap::new();
4324
4325        let rib_input_key = "request";
4326        let rib_input_value = ValueAndType::new(
4327            Value::Record(vec![Value::Record(vec![
4328                Value::String("mac-book".to_string()),
4329                Value::String("mac".to_string()),
4330                Value::U32(1),
4331                Value::F32(1.0),
4332            ])]),
4333            record(vec![field(
4334                "body",
4335                record(vec![
4336                    field("name", str()),
4337                    field("product-id", str()),
4338                    field("quantity", u32()),
4339                    field("price", f32()),
4340                ]),
4341            )]),
4342        );
4343
4344        input.insert(rib_input_key.to_string(), rib_input_value);
4345
4346        let rib_input = RibInput::new(input);
4347
4348        let mut rib_interpreter = test_utils::interpreter_static_response(
4349            &"success".into_value_and_type(),
4350            Some(rib_input),
4351        );
4352
4353        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4354
4355        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4356    }
4357
4358    #[test]
4359    async fn test_interpreter_durable_worker_with_resource_19() {
4360        let expr = r#"
4361
4362            let initial = 1: u64;
4363            let final = 5: u64;
4364            let range = initial..final;
4365
4366            for i in range {
4367                let worker = instance("my-worker");
4368                let cart = worker.cart[golem:it]("bar");
4369                yield cart.add-item(request.body);
4370            };
4371
4372            "success"
4373        "#;
4374        let expr = Expr::from_text(expr).unwrap();
4375        let component_metadata = test_utils::get_metadata_with_resource_with_params();
4376
4377        let compiled = compiler::compile(expr, &component_metadata).unwrap();
4378
4379        let mut input = HashMap::new();
4380
4381        let rib_input_key = "request";
4382        let rib_input_value = ValueAndType::new(
4383            Value::Record(vec![Value::Record(vec![
4384                Value::String("mac-book".to_string()),
4385                Value::String("mac".to_string()),
4386                Value::U32(1),
4387                Value::F32(1.0),
4388            ])]),
4389            record(vec![field(
4390                "body",
4391                record(vec![
4392                    field("name", str()),
4393                    field("product-id", str()),
4394                    field("quantity", u32()),
4395                    field("price", f32()),
4396                ]),
4397            )]),
4398        );
4399
4400        input.insert(rib_input_key.to_string(), rib_input_value);
4401
4402        let rib_input = RibInput::new(input);
4403
4404        let mut rib_interpreter = test_utils::interpreter_static_response(
4405            &"success".into_value_and_type(),
4406            Some(rib_input),
4407        );
4408
4409        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4410
4411        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4412    }
4413
4414    mod test_utils {
4415        use crate::interpreter::rib_interpreter::Interpreter;
4416        use crate::{
4417            EvaluatedFnArgs, EvaluatedFqFn, EvaluatedWorkerName, GetLiteralValue,
4418            RibFunctionInvoke, RibInput,
4419        };
4420        use async_trait::async_trait;
4421        use golem_wasm_ast::analysis::analysed_type::{
4422            case, f32, field, handle, list, option, r#enum, record, result, str, tuple, u32, u64,
4423            unit_case, variant,
4424        };
4425        use golem_wasm_ast::analysis::{
4426            AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedFunctionResult,
4427            AnalysedInstance, AnalysedResourceId, AnalysedResourceMode, AnalysedType,
4428        };
4429        use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType};
4430        use std::sync::Arc;
4431
4432        pub(crate) fn strip_spaces(input: &str) -> String {
4433            let lines = input.lines();
4434
4435            let first_line = lines
4436                .clone()
4437                .find(|line| !line.trim().is_empty())
4438                .unwrap_or("");
4439            let margin_width = first_line.chars().take_while(|c| c.is_whitespace()).count();
4440
4441            let result = lines
4442                .map(|line| {
4443                    if line.trim().is_empty() {
4444                        String::new()
4445                    } else {
4446                        line[margin_width..].to_string()
4447                    }
4448                })
4449                .collect::<Vec<String>>()
4450                .join("\n");
4451
4452            result.strip_prefix("\n").unwrap_or(&result).to_string()
4453        }
4454
4455        pub(crate) fn get_analysed_type_variant() -> AnalysedType {
4456            variant(vec![
4457                case("register-user", u64()),
4458                case("process-user", str()),
4459                unit_case("validate"),
4460            ])
4461        }
4462
4463        pub(crate) fn get_analysed_type_record() -> AnalysedType {
4464            record(vec![
4465                field(
4466                    "request",
4467                    record(vec![field("path", record(vec![field("user", str())]))]),
4468                ),
4469                field("y", str()),
4470            ])
4471        }
4472
4473        pub(crate) fn get_analysed_type_result() -> AnalysedType {
4474            result(u64(), str())
4475        }
4476
4477        pub(crate) fn get_analysed_type_enum() -> AnalysedType {
4478            r#enum(&["prod", "dev", "test"])
4479        }
4480
4481        pub(crate) fn get_analysed_typ_str() -> AnalysedType {
4482            str()
4483        }
4484
4485        pub(crate) fn get_analysed_typ_u64() -> AnalysedType {
4486            u64()
4487        }
4488
4489        pub(crate) fn get_analysed_type_tuple() -> AnalysedType {
4490            tuple(vec![
4491                get_analysed_typ_u64(),
4492                get_analysed_type_result(),
4493                get_analysed_typ_str(),
4494                get_analysed_type_record(),
4495                get_analysed_type_variant(),
4496                get_analysed_type_variant(),
4497                get_analysed_type_variant(),
4498                get_analysed_type_enum(),
4499                get_analysed_type_enum(),
4500                get_analysed_type_enum(),
4501            ])
4502        }
4503
4504        pub(crate) fn get_component_metadata(
4505            function_name: &str,
4506            input_types: Vec<AnalysedType>,
4507            output: Option<AnalysedType>,
4508        ) -> Vec<AnalysedExport> {
4509            let analysed_function_parameters = input_types
4510                .into_iter()
4511                .enumerate()
4512                .map(|(index, typ)| AnalysedFunctionParameter {
4513                    name: format!("param{}", index),
4514                    typ,
4515                })
4516                .collect();
4517
4518            let results = if let Some(output) = output {
4519                vec![AnalysedFunctionResult {
4520                    name: None,
4521                    typ: output,
4522                }]
4523            } else {
4524                // Representing Unit
4525                vec![]
4526            };
4527
4528            vec![AnalysedExport::Function(AnalysedFunction {
4529                name: function_name.to_string(),
4530                parameters: analysed_function_parameters,
4531                results,
4532            })]
4533        }
4534
4535        pub(crate) fn get_metadata_with_resource_with_params() -> Vec<AnalysedExport> {
4536            get_metadata_with_resource(vec![AnalysedFunctionParameter {
4537                name: "user-id".to_string(),
4538                typ: str(),
4539            }])
4540        }
4541
4542        pub(crate) fn get_metadata_with_resource_without_params() -> Vec<AnalysedExport> {
4543            get_metadata_with_resource(vec![])
4544        }
4545
4546        pub(crate) fn get_metadata() -> Vec<AnalysedExport> {
4547            // Exist in only amazon:shopping-cart/api1
4548            let analysed_function_in_api1 = AnalysedFunction {
4549                name: "foo".to_string(),
4550                parameters: vec![AnalysedFunctionParameter {
4551                    name: "arg1".to_string(),
4552                    typ: str(),
4553                }],
4554                results: vec![AnalysedFunctionResult {
4555                    name: None,
4556                    typ: str(),
4557                }],
4558            };
4559
4560            // Exist in both amazon:shopping-cart/api1 and amazon:shopping-cart/api2
4561            let analysed_function_in_api1_and_api2 = AnalysedFunction {
4562                name: "bar".to_string(),
4563                parameters: vec![AnalysedFunctionParameter {
4564                    name: "arg1".to_string(),
4565                    typ: str(),
4566                }],
4567                results: vec![AnalysedFunctionResult {
4568                    name: None,
4569                    typ: str(),
4570                }],
4571            };
4572
4573            // Exist in only wasi:clocks/monotonic-clock
4574            let analysed_function_in_wasi = AnalysedFunction {
4575                name: "baz".to_string(),
4576                parameters: vec![AnalysedFunctionParameter {
4577                    name: "arg1".to_string(),
4578                    typ: str(),
4579                }],
4580                results: vec![AnalysedFunctionResult {
4581                    name: None,
4582                    typ: str(),
4583                }],
4584            };
4585
4586            // Exist in wasi:clocks/monotonic-clock and amazon:shopping-cart/api1
4587            let analysed_function_in_wasi_and_api1 = AnalysedFunction {
4588                name: "qux".to_string(),
4589                parameters: vec![AnalysedFunctionParameter {
4590                    name: "arg1".to_string(),
4591                    typ: str(),
4592                }],
4593                results: vec![AnalysedFunctionResult {
4594                    name: None,
4595                    typ: str(),
4596                }],
4597            };
4598
4599            let analysed_export1 = AnalysedExport::Instance(AnalysedInstance {
4600                name: "amazon:shopping-cart/api1".to_string(),
4601                functions: vec![
4602                    analysed_function_in_api1,
4603                    analysed_function_in_api1_and_api2.clone(),
4604                    analysed_function_in_wasi_and_api1.clone(),
4605                ],
4606            });
4607
4608            let analysed_export2 = AnalysedExport::Instance(AnalysedInstance {
4609                name: "amazon:shopping-cart/api2".to_string(),
4610                functions: vec![analysed_function_in_api1_and_api2],
4611            });
4612
4613            let analysed_export3 = AnalysedExport::Instance(AnalysedInstance {
4614                name: "wasi:clocks/monotonic-clock".to_string(),
4615                functions: vec![
4616                    analysed_function_in_wasi,
4617                    analysed_function_in_wasi_and_api1,
4618                ],
4619            });
4620
4621            vec![analysed_export1, analysed_export2, analysed_export3]
4622        }
4623
4624        fn get_metadata_with_resource(
4625            resource_constructor_params: Vec<AnalysedFunctionParameter>,
4626        ) -> Vec<AnalysedExport> {
4627            let instance = AnalysedExport::Instance(AnalysedInstance {
4628                name: "golem:it/api".to_string(),
4629                functions: vec![
4630                    AnalysedFunction {
4631                        name: "[constructor]cart".to_string(),
4632                        parameters: resource_constructor_params,
4633                        results: vec![AnalysedFunctionResult {
4634                            name: None,
4635                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4636                        }],
4637                    },
4638                    AnalysedFunction {
4639                        name: "[method]cart.add-item".to_string(),
4640                        parameters: vec![
4641                            AnalysedFunctionParameter {
4642                                name: "self".to_string(),
4643                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4644                            },
4645                            AnalysedFunctionParameter {
4646                                name: "item".to_string(),
4647                                typ: record(vec![
4648                                    field("product-id", str()),
4649                                    field("name", str()),
4650                                    field("price", f32()),
4651                                    field("quantity", u32()),
4652                                ]),
4653                            },
4654                        ],
4655                        results: vec![],
4656                    },
4657                    AnalysedFunction {
4658                        name: "[method]cart.remove-item".to_string(),
4659                        parameters: vec![
4660                            AnalysedFunctionParameter {
4661                                name: "self".to_string(),
4662                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4663                            },
4664                            AnalysedFunctionParameter {
4665                                name: "product-id".to_string(),
4666                                typ: str(),
4667                            },
4668                        ],
4669                        results: vec![],
4670                    },
4671                    AnalysedFunction {
4672                        name: "[method]cart.update-item-quantity".to_string(),
4673                        parameters: vec![
4674                            AnalysedFunctionParameter {
4675                                name: "self".to_string(),
4676                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4677                            },
4678                            AnalysedFunctionParameter {
4679                                name: "product-id".to_string(),
4680                                typ: str(),
4681                            },
4682                            AnalysedFunctionParameter {
4683                                name: "quantity".to_string(),
4684                                typ: u32(),
4685                            },
4686                        ],
4687                        results: vec![],
4688                    },
4689                    AnalysedFunction {
4690                        name: "[method]cart.checkout".to_string(),
4691                        parameters: vec![AnalysedFunctionParameter {
4692                            name: "self".to_string(),
4693                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4694                        }],
4695                        results: vec![AnalysedFunctionResult {
4696                            name: None,
4697                            typ: variant(vec![
4698                                case("error", str()),
4699                                case("success", record(vec![field("order-id", str())])),
4700                            ]),
4701                        }],
4702                    },
4703                    AnalysedFunction {
4704                        name: "[method]cart.get-cart-contents".to_string(),
4705                        parameters: vec![AnalysedFunctionParameter {
4706                            name: "self".to_string(),
4707                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4708                        }],
4709                        results: vec![AnalysedFunctionResult {
4710                            name: None,
4711                            typ: list(record(vec![
4712                                field("product-id", str()),
4713                                field("name", str()),
4714                                field("price", f32()),
4715                                field("quantity", u32()),
4716                            ])),
4717                        }],
4718                    },
4719                    AnalysedFunction {
4720                        name: "[method]cart.merge-with".to_string(),
4721                        parameters: vec![
4722                            AnalysedFunctionParameter {
4723                                name: "self".to_string(),
4724                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4725                            },
4726                            AnalysedFunctionParameter {
4727                                name: "other-cart".to_string(),
4728                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4729                            },
4730                        ],
4731                        results: vec![],
4732                    },
4733                    AnalysedFunction {
4734                        name: "[drop]cart".to_string(),
4735                        parameters: vec![AnalysedFunctionParameter {
4736                            name: "self".to_string(),
4737                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4738                        }],
4739                        results: vec![],
4740                    },
4741                ],
4742            });
4743
4744            vec![instance]
4745        }
4746
4747        pub(crate) fn get_value_and_type(
4748            analysed_type: &AnalysedType,
4749            wasm_wave_str: &str,
4750        ) -> ValueAndType {
4751            golem_wasm_rpc::parse_value_and_type(analysed_type, wasm_wave_str).unwrap()
4752        }
4753
4754        // The interpreter that always returns a static value for every function calls in Rib
4755        // regardless of the input arguments
4756        pub(crate) fn interpreter_static_response(
4757            result_value: &ValueAndType,
4758            input: Option<RibInput>,
4759        ) -> Interpreter {
4760            let value = result_value.clone();
4761
4762            let invoke = Arc::new(TestInvoke1 { value });
4763
4764            Interpreter {
4765                input: input.unwrap_or_default(),
4766                invoke,
4767                custom_stack: None,
4768                custom_env: None,
4769            }
4770        }
4771
4772        // The interpreter that always returns a record value consisting of function name, worker name etc
4773        // for every function calls in Rib.
4774        // Example : `my-instance.qux[amazon:shopping-cart]("bar")` will return a record
4775        // that contains the actual worker-name of my-instance, the function name `qux` and arguments
4776        // It helps ensures that interpreter invokes the function at the expected worker.
4777        pub(crate) fn interpreter_worker_details_response(
4778            rib_input: Option<RibInput>,
4779        ) -> Interpreter {
4780            let invoke: Arc<dyn RibFunctionInvoke + Send + Sync> = Arc::new(TestInvoke2);
4781
4782            Interpreter {
4783                input: rib_input.unwrap_or_default(),
4784                invoke,
4785                custom_stack: None,
4786                custom_env: None,
4787            }
4788        }
4789
4790        // A simple interpreter that returns response based on the function
4791        pub(crate) fn interpreter_dynamic_response(input: Option<RibInput>) -> Interpreter {
4792            let invoke = Arc::new(TestInvoke3);
4793
4794            Interpreter {
4795                input: input.unwrap_or_default(),
4796                invoke,
4797                custom_stack: None,
4798                custom_env: None,
4799            }
4800        }
4801
4802        pub(crate) fn parse_function_details(input: &str) -> ValueAndType {
4803            let analysed_type = record(vec![
4804                field("worker-name", option(str())),
4805                field("function-name", str()),
4806                field("args0", str()),
4807            ]);
4808
4809            get_value_and_type(&analysed_type, input)
4810        }
4811
4812        struct TestInvoke1 {
4813            value: ValueAndType,
4814        }
4815
4816        #[async_trait]
4817        impl RibFunctionInvoke for TestInvoke1 {
4818            async fn invoke(
4819                &self,
4820                _worker_name: Option<EvaluatedWorkerName>,
4821                _fqn: EvaluatedFqFn,
4822                _args: EvaluatedFnArgs,
4823            ) -> Result<ValueAndType, String> {
4824                let value = self.value.clone();
4825                Ok(ValueAndType::new(
4826                    Value::Tuple(vec![value.value]),
4827                    tuple(vec![value.typ]),
4828                ))
4829            }
4830        }
4831
4832        struct TestInvoke2;
4833
4834        #[async_trait]
4835        impl RibFunctionInvoke for TestInvoke2 {
4836            async fn invoke(
4837                &self,
4838                worker_name: Option<EvaluatedWorkerName>,
4839                function_name: EvaluatedFqFn,
4840                args: EvaluatedFnArgs,
4841            ) -> Result<ValueAndType, String> {
4842                let worker_name = worker_name.map(|x| x.0);
4843
4844                let function_name = function_name.0.into_value_and_type();
4845
4846                let args = args.0;
4847
4848                let mut arg_types = vec![];
4849
4850                for (index, value_and_type) in args.iter().enumerate() {
4851                    let name = format!("args{}", index);
4852                    let value = value_and_type.typ.clone();
4853                    arg_types.push(field(name.as_str(), value));
4854                }
4855
4856                let mut analysed_type_pairs = vec![];
4857                analysed_type_pairs.push(field("worker-name", option(str())));
4858                analysed_type_pairs.push(field("function-name", str()));
4859                analysed_type_pairs.extend(arg_types);
4860
4861                let mut values = vec![];
4862
4863                values.push(Value::Option(
4864                    worker_name.map(|x| Box::new(Value::String(x))),
4865                ));
4866                values.push(function_name.value);
4867
4868                for arg_value in args {
4869                    values.push(arg_value.value);
4870                }
4871
4872                let value = ValueAndType::new(
4873                    Value::Tuple(vec![Value::Record(values)]),
4874                    tuple(vec![record(analysed_type_pairs)]),
4875                );
4876                Ok(value)
4877            }
4878        }
4879
4880        pub(crate) fn get_metadata_with_enum_and_variant() -> Vec<AnalysedExport> {
4881            vec![
4882                AnalysedExport::Function(AnalysedFunction {
4883                    name: "add-u32".to_string(),
4884                    parameters: vec![
4885                        AnalysedFunctionParameter {
4886                            name: "param1".to_string(),
4887                            typ: u32(),
4888                        },
4889                        AnalysedFunctionParameter {
4890                            name: "param2".to_string(),
4891                            typ: u32(),
4892                        },
4893                    ],
4894                    results: vec![AnalysedFunctionResult {
4895                        name: None,
4896                        typ: u32(),
4897                    }],
4898                }),
4899                AnalysedExport::Function(AnalysedFunction {
4900                    name: "add-u64".to_string(),
4901                    parameters: vec![
4902                        AnalysedFunctionParameter {
4903                            name: "param1".to_string(),
4904                            typ: u64(),
4905                        },
4906                        AnalysedFunctionParameter {
4907                            name: "param2".to_string(),
4908                            typ: u64(),
4909                        },
4910                    ],
4911                    results: vec![AnalysedFunctionResult {
4912                        name: None,
4913                        typ: u64(),
4914                    }],
4915                }),
4916                AnalysedExport::Function(AnalysedFunction {
4917                    name: "add-enum".to_string(),
4918                    parameters: vec![
4919                        AnalysedFunctionParameter {
4920                            name: "param1".to_string(),
4921                            typ: r#enum(&["x", "y", "z"]),
4922                        },
4923                        AnalysedFunctionParameter {
4924                            name: "param2".to_string(),
4925                            typ: r#enum(&["x", "y", "z"]),
4926                        },
4927                    ],
4928                    results: vec![AnalysedFunctionResult {
4929                        name: None,
4930                        typ: r#enum(&["x", "y", "z"]),
4931                    }],
4932                }),
4933                AnalysedExport::Function(AnalysedFunction {
4934                    name: "add-variant".to_string(),
4935                    parameters: vec![
4936                        AnalysedFunctionParameter {
4937                            name: "param1".to_string(),
4938                            typ: get_analysed_type_variant(),
4939                        },
4940                        AnalysedFunctionParameter {
4941                            name: "param2".to_string(),
4942                            typ: get_analysed_type_variant(),
4943                        },
4944                    ],
4945                    results: vec![AnalysedFunctionResult {
4946                        name: None,
4947                        typ: get_analysed_type_variant(),
4948                    }],
4949                }),
4950            ]
4951        }
4952
4953        struct TestInvoke3;
4954
4955        #[async_trait]
4956        impl RibFunctionInvoke for TestInvoke3 {
4957            async fn invoke(
4958                &self,
4959                _worker_name: Option<EvaluatedWorkerName>,
4960                function_name: EvaluatedFqFn,
4961                args: EvaluatedFnArgs,
4962            ) -> Result<ValueAndType, String> {
4963                match function_name.0.as_str() {
4964                    "add-u32" => {
4965                        let args = args.0;
4966                        let arg1 = args[0].get_literal().and_then(|x| x.get_number()).unwrap();
4967                        let arg2 = args[1].get_literal().and_then(|x| x.get_number()).unwrap();
4968                        let result = arg1 + arg2;
4969                        let u32 = result.cast_to(&u32()).unwrap();
4970
4971                        Ok(ValueAndType::new(
4972                            Value::Tuple(vec![u32.value]),
4973                            tuple(vec![u32.typ]),
4974                        ))
4975                    }
4976                    "add-u64" => {
4977                        let args = args.0;
4978                        let arg1 = args[0].get_literal().and_then(|x| x.get_number()).unwrap();
4979                        let arg2 = args[1].get_literal().and_then(|x| x.get_number()).unwrap();
4980                        let result = arg1 + arg2;
4981                        let u64 = result.cast_to(&u64()).unwrap();
4982                        Ok(ValueAndType::new(
4983                            Value::Tuple(vec![u64.value]),
4984                            tuple(vec![u64.typ]),
4985                        ))
4986                    }
4987                    "add-enum" => {
4988                        let args = args.0;
4989                        let arg1 = args[0].clone().value;
4990                        let arg2 = args[1].clone().value;
4991                        match (arg1, arg2) {
4992                            (Value::Enum(x), Value::Enum(y)) => {
4993                                if x == y {
4994                                    let result =
4995                                        ValueAndType::new(Value::Enum(x), r#enum(&["x", "y", "z"]));
4996                                    Ok(ValueAndType::new(
4997                                        Value::Tuple(vec![result.value]),
4998                                        tuple(vec![result.typ]),
4999                                    ))
5000                                } else {
5001                                    Err(format!("Enums are not equal: {} and {}", x, y))
5002                                }
5003                            }
5004                            (v1, v2) => Err(format!(
5005                                "Invalid arguments for add-enum: {:?} and {:?}",
5006                                v1, v2
5007                            )),
5008                        }
5009                    }
5010                    "add-variant" => {
5011                        let args = args.0;
5012                        let arg1 = args[0].clone().value;
5013                        let arg2 = args[1].clone().value;
5014                        match (arg1, arg2) {
5015                            (
5016                                Value::Variant {
5017                                    case_idx: case_idx1,
5018                                    case_value,
5019                                },
5020                                Value::Variant {
5021                                    case_idx: case_idx2,
5022                                    ..
5023                                },
5024                            ) => {
5025                                if case_idx1 == case_idx2 {
5026                                    let result = ValueAndType::new(
5027                                        Value::Variant {
5028                                            case_idx: case_idx1,
5029                                            case_value,
5030                                        },
5031                                        get_analysed_type_variant(),
5032                                    );
5033                                    Ok(ValueAndType::new(
5034                                        Value::Tuple(vec![result.value]),
5035                                        tuple(vec![result.typ]),
5036                                    ))
5037                                } else {
5038                                    Err(format!(
5039                                        "Variants are not equal: {} and {}",
5040                                        case_idx1, case_idx2
5041                                    ))
5042                                }
5043                            }
5044                            (v1, v2) => Err(format!(
5045                                "Invalid arguments for add-variant: {:?} and {:?}",
5046                                v1, v2
5047                            )),
5048                        }
5049                    }
5050                    fun => Err(format!("unknown function {}", fun)),
5051                }
5052            }
5053        }
5054    }
5055}