rib/interpreter/
rib_interpreter.rs

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