Skip to main content

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::wit_type::TypeResult;
354    use crate::wit_type::WitType;
355    use crate::{
356        bail_corrupted_state, internal_corrupted_state, CoercedNumericValue,
357        ComponentDependencyKey, EvaluatedFnArgs, EvaluatedFqFn, EvaluatedWorkerName,
358        FunctionReferenceType, GetLiteralValue, InstanceVariable, InstructionId, Interpreter,
359        ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite,
360        RibComponentFunctionInvoke, RibFunctionInvokeResult, RibInterpreterResult, TypeHint,
361        VariableId, WitTypeWithUnit,
362    };
363    use crate::{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 crate::wit_type::{s16, s32, s64, s8, str, u16, u32, u64, u8};
374    use async_trait::async_trait;
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: EvaluatedWorkerName,
386            _function_name: EvaluatedFqFn,
387            _args: EvaluatedFnArgs,
388            _return_type: Option<WitType>,
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), WitType::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), WitType::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: WitType,
586    ) -> RibInterpreterResult<()> {
587        let analysed_type = match analysed_type {
588            WitType::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: WitType,
772        interpreter_stack: &mut InterpreterStack,
773    ) -> RibInterpreterResult<()> {
774        let name_type_pair = match analysed_type {
775            WitType::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: WitType::Record(record_type),
817        });
818        Ok(())
819    }
820
821    pub(crate) fn run_push_list_instruction(
822        list_size: usize,
823        analysed_type: WitType,
824        interpreter_stack: &mut InterpreterStack,
825    ) -> RibInterpreterResult<()> {
826        match analysed_type {
827            WitType::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: WitType,
848        interpreter_stack: &mut InterpreterStack,
849    ) -> RibInterpreterResult<()> {
850        match analysed_type {
851            WitType::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: &WitType,
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: WitType::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: WitType::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: WitType::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: WitType::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: WitType::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: WitType,
1088    ) -> RibInterpreterResult<()> {
1089        match analysed_type {
1090            WitType::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: WitType,
1104        interpreter_stack: &mut InterpreterStack,
1105    ) -> RibInterpreterResult<()> {
1106        match analysed_type {
1107            WitType::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        }
1185
1186        Ok(())
1187    }
1188
1189    pub(crate) async fn run_invoke_function_instruction(
1190        component_info: ComponentDependencyKey,
1191        instruction_id: &InstructionId,
1192        arg_size: usize,
1193        instance_variable_type: InstanceVariable,
1194        interpreter_stack: &mut InterpreterStack,
1195        interpreter_env: &mut InterpreterEnv,
1196        expected_result_type: WitTypeWithUnit,
1197    ) -> RibInterpreterResult<()> {
1198        let function_name = interpreter_stack
1199            .pop_str()
1200            .ok_or_else(|| internal_corrupted_state!("failed to get a function name"))?;
1201
1202        let function_name_cloned = function_name.clone();
1203
1204        let last_n_elements = interpreter_stack
1205            .pop_n(arg_size)
1206            .ok_or_else(|| insufficient_stack_items(arg_size))?;
1207
1208        let expected_result_type = match expected_result_type {
1209            WitTypeWithUnit::Type(analysed_type) => Some(analysed_type),
1210            WitTypeWithUnit::Unit => None,
1211        };
1212
1213        let parameter_values = last_n_elements
1214            .iter()
1215            .map(|interpreter_result| {
1216                interpreter_result.get_val().ok_or_else(|| {
1217                    internal_corrupted_state!("failed to call function {}", function_name)
1218                })
1219            })
1220            .collect::<RibInterpreterResult<Vec<ValueAndType>>>()?;
1221
1222        match instance_variable_type {
1223            InstanceVariable::WitWorker(variable_id) => {
1224                let worker_id = interpreter_env
1225                    .lookup(&EnvironmentKey::from(variable_id.clone()))
1226                    .map(|x| {
1227                        x.get_val().ok_or_else(|| {
1228                            internal_corrupted_state!(
1229                                "failed to get a worker variable id for function {}",
1230                                function_name
1231                            )
1232                        })
1233                    })
1234                    .transpose()?
1235                    .ok_or_else(|| {
1236                        internal_corrupted_state!(
1237                            "failed to find a worker with id {}",
1238                            variable_id.name()
1239                        )
1240                    })?;
1241
1242                let worker_id_string =
1243                    worker_id
1244                        .get_literal()
1245                        .map(|v| v.as_string())
1246                        .ok_or_else(|| {
1247                            internal_corrupted_state!("failed to get a worker name for variable")
1248                        })?;
1249
1250                let result = interpreter_env
1251                    .invoke_worker_function_async(
1252                        component_info,
1253                        instruction_id,
1254                        worker_id_string,
1255                        function_name_cloned,
1256                        parameter_values,
1257                        expected_result_type.clone(),
1258                    )
1259                    .await
1260                    .map_err(|err| function_invoke_fail(function_name.as_str(), err))?;
1261
1262                match result {
1263                    None => {
1264                        interpreter_stack.push(RibInterpreterStackValue::Unit);
1265                    }
1266                    Some(result) => {
1267                        interpreter_stack.push(RibInterpreterStackValue::Val(result));
1268                    }
1269                }
1270            }
1271
1272            InstanceVariable::WitResource(variable_id)
1273                if variable_id == VariableId::global("___STATIC_WIT_RESOURCE".to_string()) =>
1274            {
1275                let result = interpreter_env
1276                    .invoke_worker_function_async(
1277                        component_info,
1278                        instruction_id,
1279                        "___STATIC_WIT_RESOURCE".to_string(),
1280                        function_name_cloned,
1281                        parameter_values,
1282                        expected_result_type.clone(),
1283                    )
1284                    .await
1285                    .map_err(|err| function_invoke_fail(function_name.as_str(), err))?;
1286
1287                match result {
1288                    None => {
1289                        interpreter_stack.push(RibInterpreterStackValue::Unit);
1290                    }
1291                    Some(result) => {
1292                        interpreter_stack.push(RibInterpreterStackValue::Val(result));
1293                    }
1294                }
1295            }
1296
1297            InstanceVariable::WitResource(variable_id) => {
1298                let mut final_args = vec![];
1299
1300                let handle = interpreter_env
1301                    .lookup(&EnvironmentKey::from(variable_id.clone()))
1302                    .map(|x| {
1303                        x.get_val().ok_or_else(|| {
1304                            internal_corrupted_state!(
1305                                "failed to get a resource with id {}",
1306                                variable_id.name()
1307                            )
1308                        })
1309                    })
1310                    .transpose()?
1311                    .ok_or_else(|| {
1312                        internal_corrupted_state!(
1313                            "failed to find a resource with id {}",
1314                            variable_id.name()
1315                        )
1316                    })?;
1317
1318                match &handle.value {
1319                    Value::Handle { uri, .. } => {
1320                        let worker_name = uri.rsplit_once('/').map(|(_, last)| last).unwrap_or(uri);
1321
1322                        final_args.push(handle.clone());
1323                        final_args.extend(parameter_values);
1324
1325                        let result = interpreter_env
1326                            .invoke_worker_function_async(
1327                                component_info,
1328                                instruction_id,
1329                                worker_name.to_string(),
1330                                function_name_cloned.clone(),
1331                                final_args,
1332                                expected_result_type.clone(),
1333                            )
1334                            .await
1335                            .map_err(|err| function_invoke_fail(function_name.as_str(), err))?;
1336
1337                        match result {
1338                            None => {
1339                                interpreter_stack.push(RibInterpreterStackValue::Unit);
1340                            }
1341                            Some(result) => {
1342                                interpreter_stack.push(RibInterpreterStackValue::Val(result));
1343                            }
1344                        }
1345                    }
1346
1347                    _ => {
1348                        return Err(function_invoke_fail(
1349                            function_name.as_str(),
1350                            "expected the result of a resource construction to be of type `handle`"
1351                                .into(),
1352                        ))
1353                    }
1354                };
1355            }
1356        };
1357
1358        Ok(())
1359    }
1360
1361    pub(crate) fn run_deconstruct_instruction(
1362        interpreter_stack: &mut InterpreterStack,
1363    ) -> RibInterpreterResult<()> {
1364        let value = interpreter_stack
1365            .pop()
1366            .ok_or_else(|| internal_corrupted_state!("no value to unwrap"))?;
1367
1368        let unwrapped_value = value
1369            .unwrap()
1370            .ok_or_else(|| internal_corrupted_state!("failed to unwrap the value {}", value))?;
1371
1372        interpreter_stack.push_val(unwrapped_value);
1373        Ok(())
1374    }
1375
1376    pub(crate) fn run_get_tag_instruction(
1377        interpreter_stack: &mut InterpreterStack,
1378    ) -> RibInterpreterResult<()> {
1379        let value = interpreter_stack
1380            .pop_val()
1381            .ok_or_else(|| internal_corrupted_state!("failed to get a tag value"))?;
1382
1383        let tag = match value {
1384            ValueAndType {
1385                value: Value::Variant { case_idx, .. },
1386                typ: WitType::Variant(typ),
1387            } => typ.cases[case_idx as usize].name.clone(),
1388            ValueAndType {
1389                value: Value::Option(option),
1390                ..
1391            } => match option {
1392                Some(_) => "some".to_string(),
1393                None => "none".to_string(),
1394            },
1395            ValueAndType {
1396                value: Value::Result(result_value),
1397                ..
1398            } => match result_value {
1399                Ok(_) => "ok".to_string(),
1400                Err(_) => "err".to_string(),
1401            },
1402            ValueAndType {
1403                value: Value::Enum(idx),
1404                typ: WitType::Enum(typ),
1405            } => typ.cases[idx as usize].clone(),
1406            _ => "untagged".to_string(),
1407        };
1408
1409        interpreter_stack.push_val(tag.into_value_and_type());
1410        Ok(())
1411    }
1412
1413    pub(crate) fn run_create_some_instruction(
1414        interpreter_stack: &mut InterpreterStack,
1415        analysed_type: WitType,
1416    ) -> RibInterpreterResult<()> {
1417        let value = interpreter_stack.try_pop_val()?;
1418
1419        match analysed_type {
1420            WitType::Option(analysed_type) => {
1421                interpreter_stack.push_some(value.value, analysed_type.inner.deref());
1422                Ok(())
1423            }
1424            _ => Err(type_mismatch_with_type_hint(
1425                vec![TypeHint::Option(None)],
1426                analysed_type.get_type_hint(),
1427            )),
1428        }
1429    }
1430
1431    pub(crate) fn run_create_none_instruction(
1432        interpreter_stack: &mut InterpreterStack,
1433        analysed_type: Option<WitType>,
1434    ) -> RibInterpreterResult<()> {
1435        match analysed_type {
1436            Some(WitType::Option(_)) | None => {
1437                interpreter_stack.push_none(analysed_type);
1438                Ok(())
1439            }
1440            _ => Err(type_mismatch_with_type_hint(
1441                vec![TypeHint::Option(None)],
1442                analysed_type
1443                    .as_ref()
1444                    .map(|t| t.get_type_hint())
1445                    .unwrap_or_else(|| TypeHint::Unknown),
1446            )),
1447        }
1448    }
1449
1450    pub(crate) fn run_create_ok_instruction(
1451        interpreter_stack: &mut InterpreterStack,
1452        analysed_type: WitType,
1453    ) -> RibInterpreterResult<()> {
1454        let value = interpreter_stack.try_pop_val()?;
1455
1456        match analysed_type {
1457            WitType::Result(TypeResult { ok, err, .. }) => {
1458                interpreter_stack.push_ok(value.value, ok.as_deref(), err.as_deref());
1459                Ok(())
1460            }
1461            _ => Err(type_mismatch_with_type_hint(
1462                vec![TypeHint::Result {
1463                    ok: None,
1464                    err: None,
1465                }],
1466                analysed_type.get_type_hint(),
1467            )),
1468        }
1469    }
1470
1471    pub(crate) fn run_create_err_instruction(
1472        interpreter_stack: &mut InterpreterStack,
1473        analysed_type: WitType,
1474    ) -> RibInterpreterResult<()> {
1475        let value = interpreter_stack.try_pop_val()?;
1476
1477        match analysed_type {
1478            WitType::Result(TypeResult { ok, err, .. }) => {
1479                interpreter_stack.push_err(value.value, ok.as_deref(), err.as_deref());
1480                Ok(())
1481            }
1482            _ => Err(type_mismatch_with_type_hint(
1483                vec![TypeHint::Result {
1484                    ok: None,
1485                    err: None,
1486                }],
1487                analysed_type.get_type_hint(),
1488            )),
1489        }
1490    }
1491
1492    pub(crate) fn run_concat_instruction(
1493        interpreter_stack: &mut InterpreterStack,
1494        arg_size: usize,
1495    ) -> RibInterpreterResult<()> {
1496        let value_and_types = interpreter_stack.try_pop_n_val(arg_size)?;
1497
1498        let mut result = String::new();
1499
1500        for val in value_and_types {
1501            match &val.value {
1502                Value::String(s) => {
1503                    // Avoid extra quotes when concatenating strings
1504                    result.push_str(s);
1505                }
1506                Value::Char(char) => {
1507                    // Avoid extra single quotes when concatenating chars
1508                    result.push(*char);
1509                }
1510                _ => {
1511                    result.push_str(&val.to_string());
1512                }
1513            }
1514        }
1515
1516        interpreter_stack.push_val(result.into_value_and_type());
1517
1518        Ok(())
1519    }
1520}
1521
1522#[cfg(test)]
1523mod tests {
1524    use std::collections::HashMap;
1525    use test_r::test;
1526
1527    use super::*;
1528    use crate::interpreter::rib_interpreter::tests::test_utils::{
1529        get_analysed_type_variant, get_value_and_type, strip_spaces, RibTestDeps,
1530    };
1531    use crate::wit_type::WitType;
1532    use crate::wit_type::{
1533        bool, case, f32, field, list, option, r#enum, record, result, result_err, result_ok, s32,
1534        str, tuple, u32, u64, u8, unit_case, variant,
1535    };
1536    use crate::{
1537        ComponentDependency, CustomInstanceSpec, Expr, GlobalVariableTypeSpec, InferredType,
1538        InstructionId, Path, RibCompiler, RibCompilerConfig, VariableId,
1539    };
1540    use crate::{IntoValue, IntoValueAndType, Value, ValueAndType};
1541
1542    #[test]
1543    async fn interpreter_push_literal() {
1544        let mut interpreter = Interpreter::default();
1545
1546        let instructions = RibByteCode {
1547            instructions: vec![RibIR::PushLit(1i32.into_value_and_type())],
1548        };
1549
1550        let result = interpreter.run(instructions).await.unwrap();
1551        assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type());
1552    }
1553
1554    #[test]
1555    async fn interpreter_bytecode_comparison_operators() {
1556        let cases = [
1557            (
1558                vec![
1559                    RibIR::PushLit(1i32.into_value_and_type()),
1560                    RibIR::PushLit(1u32.into_value_and_type()),
1561                    RibIR::EqualTo,
1562                ],
1563                true,
1564            ),
1565            (
1566                vec![
1567                    RibIR::PushLit(1i32.into_value_and_type()),
1568                    RibIR::PushLit(2u32.into_value_and_type()),
1569                    RibIR::GreaterThan,
1570                ],
1571                true,
1572            ),
1573            (
1574                vec![
1575                    RibIR::PushLit(2i32.into_value_and_type()),
1576                    RibIR::PushLit(1u32.into_value_and_type()),
1577                    RibIR::LessThan,
1578                ],
1579                true,
1580            ),
1581            (
1582                vec![
1583                    RibIR::PushLit(2i32.into_value_and_type()),
1584                    RibIR::PushLit(3u32.into_value_and_type()),
1585                    RibIR::GreaterThanOrEqualTo,
1586                ],
1587                true,
1588            ),
1589            (
1590                vec![
1591                    RibIR::PushLit(2i32.into_value_and_type()),
1592                    RibIR::PushLit(1i32.into_value_and_type()),
1593                    RibIR::LessThanOrEqualTo,
1594                ],
1595                true,
1596            ),
1597        ];
1598
1599        for (instructions, expect_true) in cases {
1600            let mut interpreter = Interpreter::default();
1601            let byte_code = RibByteCode { instructions };
1602            let result = interpreter.run(byte_code).await.unwrap();
1603            assert_eq!(result.get_bool().unwrap(), expect_true);
1604        }
1605    }
1606
1607    #[test]
1608    async fn interpreter_assign_and_load_local_binding() {
1609        let mut interpreter = Interpreter::default();
1610
1611        let instructions = RibByteCode {
1612            instructions: vec![
1613                RibIR::PushLit(1i32.into_value_and_type()),
1614                RibIR::AssignVar(VariableId::local_with_no_id("x")),
1615                RibIR::LoadVar(VariableId::local_with_no_id("x")),
1616            ],
1617        };
1618
1619        let result = interpreter.run(instructions).await.unwrap();
1620        assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type());
1621    }
1622
1623    #[test]
1624    async fn interpreter_unconditional_jump() {
1625        let mut interpreter = Interpreter::default();
1626
1627        let instructions = RibByteCode {
1628            instructions: vec![
1629                RibIR::Jump(InstructionId::init()),
1630                RibIR::PushLit(1i32.into_value_and_type()),
1631                RibIR::Label(InstructionId::init()),
1632            ],
1633        };
1634
1635        let result = interpreter.run(instructions).await;
1636        assert!(result.is_ok());
1637    }
1638
1639    #[test]
1640    async fn interpreter_jump_if_false_skips_following_instructions() {
1641        let mut interpreter = Interpreter::default();
1642
1643        let id = InstructionId::init().increment_mut();
1644
1645        let instructions = RibByteCode {
1646            instructions: vec![
1647                RibIR::PushLit(false.into_value_and_type()),
1648                RibIR::JumpIfFalse(id.clone()),
1649                RibIR::PushLit(1i32.into_value_and_type()),
1650                RibIR::Label(id),
1651            ],
1652        };
1653
1654        let result = interpreter.run(instructions).await;
1655        assert!(result.is_ok());
1656    }
1657
1658    #[test]
1659    async fn interpreter_build_record_from_stack() {
1660        let mut interpreter = Interpreter::default();
1661
1662        let instructions = RibByteCode {
1663            instructions: vec![
1664                RibIR::PushLit(2i32.into_value_and_type()),
1665                RibIR::PushLit(1i32.into_value_and_type()),
1666                RibIR::CreateAndPushRecord(record(vec![field("x", s32()), field("y", s32())])),
1667                RibIR::UpdateRecord("x".to_string()),
1668                RibIR::UpdateRecord("y".to_string()),
1669            ],
1670        };
1671
1672        let result = interpreter.run(instructions).await.unwrap();
1673        let expected = ValueAndType::new(
1674            Value::Record(vec![1i32.into_value(), 2i32.into_value()]),
1675            record(vec![field("x", s32()), field("y", s32())]),
1676        );
1677
1678        assert_eq!(result.get_val().unwrap(), expected);
1679    }
1680
1681    #[test]
1682    async fn interpreter_build_list_from_stack() {
1683        let mut interpreter = Interpreter::default();
1684
1685        let instructions = RibByteCode {
1686            instructions: vec![
1687                RibIR::PushLit(2i32.into_value_and_type()),
1688                RibIR::PushLit(1i32.into_value_and_type()),
1689                RibIR::PushList(list(s32()), 2),
1690            ],
1691        };
1692
1693        let result = interpreter.run(instructions).await.unwrap();
1694        let expected = ValueAndType::new(
1695            Value::List(vec![1i32.into_value(), 2i32.into_value()]),
1696            list(s32()),
1697        );
1698        assert_eq!(result.get_val().unwrap(), expected);
1699    }
1700
1701    #[test]
1702    async fn interpreter_select_field_from_record() {
1703        let mut interpreter = Interpreter::default();
1704
1705        let instructions = RibByteCode {
1706            instructions: vec![
1707                RibIR::PushLit(1i32.into_value_and_type()),
1708                RibIR::PushLit(2i32.into_value_and_type()),
1709                RibIR::CreateAndPushRecord(record(vec![field("x", s32())])),
1710                RibIR::UpdateRecord("x".to_string()),
1711                RibIR::SelectField("x".to_string()),
1712            ],
1713        };
1714
1715        let result = interpreter.run(instructions).await.unwrap();
1716        assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type());
1717    }
1718
1719    #[test]
1720    async fn interpreter_select_list_element_by_constant_index() {
1721        let mut interpreter = Interpreter::default();
1722
1723        let instructions = RibByteCode {
1724            instructions: vec![
1725                RibIR::PushLit(1i32.into_value_and_type()),
1726                RibIR::PushLit(2i32.into_value_and_type()),
1727                RibIR::PushList(list(s32()), 2),
1728                RibIR::SelectIndex(0),
1729            ],
1730        };
1731
1732        let result = interpreter.run(instructions).await.unwrap();
1733        assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type());
1734    }
1735
1736    #[test]
1737    async fn interpreter_let_bindings_and_shadowing() {
1738        let cases: Vec<(&str, ValueAndType)> = vec![
1739            (
1740                r#"
1741               let x = 1;
1742               let y = x + 2;
1743               y
1744            "#,
1745                3i32.into_value_and_type(),
1746            ),
1747            (
1748                r#"
1749               let x = 1;
1750               let z = {foo : x};
1751               let x = x + 2u64;
1752               { bar: x, baz: z }
1753            "#,
1754                get_value_and_type(
1755                    &record(vec![
1756                        field("bar", u64()),
1757                        field("baz", record(vec![field("foo", u64())])),
1758                    ]),
1759                    r#"{ bar: 3, baz: { foo: 1 } }"#,
1760                ),
1761            ),
1762            (
1763                r#"
1764               let x = 1;
1765               let x = x;
1766
1767               let result1 = match some(x + 1) {
1768                  some(x) => x,
1769                  none => x
1770               };
1771
1772               let z: option<u64> = none;
1773
1774               let result2 = match z {
1775                  some(x) => x,
1776                  none => x
1777               };
1778
1779               { result1: result1, result2: result2 }
1780            "#,
1781                get_value_and_type(
1782                    &record(vec![field("result1", u64()), field("result2", u64())]),
1783                    r#"{ result1: 2, result2: 1 }"#,
1784                ),
1785            ),
1786            (
1787                r#"
1788               let x = 1;
1789               let x = x;
1790
1791               let result1 = match some(x + 1) {
1792                  some(x) => match some(x + 1) {
1793                     some(x) => x,
1794                     none => x
1795                  },
1796                  none => x
1797               };
1798
1799               let z: option<u64> = none;
1800
1801               let result2 = match z {
1802                  some(x) => x,
1803                  none => match some(x + 1) {
1804                     some(x) => x,
1805                     none => x
1806                  }
1807               };
1808
1809               { result1: result1, result2: result2 }
1810            "#,
1811                get_value_and_type(
1812                    &record(vec![field("result1", u64()), field("result2", u64())]),
1813                    r#"{ result1: 3, result2: 2 }"#,
1814                ),
1815            ),
1816        ];
1817
1818        for (rib_expr, expected) in cases {
1819            let expr = Expr::from_text(rib_expr).unwrap();
1820            let mut interpreter = Interpreter::default();
1821            let compiler = RibCompiler::default();
1822            let compiled = compiler.compile(expr).unwrap();
1823            let result = interpreter.run(compiled.byte_code).await.unwrap();
1824            assert_eq!(result.get_val().unwrap(), expected);
1825        }
1826    }
1827
1828    #[test]
1829    async fn interpreter_global_variable_paths_respect_type_spec() {
1830        // request.path.user-id and request.headers.* should be inferred as string,
1831        // since we configure the compiler with a type-spec (given below)
1832        let rib_expr = r#"
1833               let res1 = request.path.user-id;
1834               let res2 = request.headers.name;
1835               let res3 = request.headers.age;
1836               "${res1}-${res2}-${res3}"
1837            "#;
1838
1839        let type_spec = vec![
1840            GlobalVariableTypeSpec::new(
1841                "request",
1842                Path::from_elems(vec!["path"]),
1843                InferredType::string(),
1844            ),
1845            GlobalVariableTypeSpec::new(
1846                "request",
1847                Path::from_elems(vec!["headers"]),
1848                InferredType::string(),
1849            ),
1850        ];
1851
1852        let mut rib_input = HashMap::new();
1853
1854        // Rib compiler identifies the input requirements to be a string (due to type-spec passed)
1855        // and therefore, we pass input value (value_and_type) to the interpreter with headers and path values as string
1856        let analysed_type_of_input = &record(vec![
1857            field("path", record(vec![field("user-id", str())])),
1858            field(
1859                "headers",
1860                record(vec![field("name", str()), field("age", str())]),
1861            ),
1862        ]);
1863
1864        let value_and_type = get_value_and_type(
1865            analysed_type_of_input,
1866            r#"{path : { user-id: "1" }, headers: { name: "foo", age: "20" }}"#,
1867        );
1868
1869        rib_input.insert("request".to_string(), value_and_type);
1870
1871        let mut interpreter =
1872            test_utils::interpreter_with_noop_function_invoke(Some(RibInput::new(rib_input)));
1873
1874        let expr = Expr::from_text(rib_expr).unwrap();
1875
1876        let compiler = RibCompiler::new(RibCompilerConfig::new(
1877            ComponentDependency::default(),
1878            type_spec,
1879            vec![],
1880        ));
1881        let compiled = compiler.compile(expr).unwrap();
1882
1883        let result = interpreter
1884            .run(compiled.byte_code)
1885            .await
1886            .unwrap()
1887            .get_val()
1888            .unwrap()
1889            .value;
1890
1891        assert_eq!(result, Value::String("1-foo-20".to_string()))
1892    }
1893
1894    #[test]
1895    async fn interpreter_global_variable_type_annotations_override_spec() {
1896        let rib_expr = r#"
1897             let res1: u32 = request.path.user-id;
1898             let res2 = request.headers.name;
1899             let res3: u32 = request.headers.age;
1900             let res4 = res1 + res3;
1901             "${res4}-${res2}"
1902            "#;
1903
1904        // We always specify the type of request.path.* and request.headers.* to be a string using type-spec
1905        // however the rib script (above) explicitly specify the type of request.path.user-id
1906        // and request.header.age to be u32. In this case, the Rib compiler infer them as u32 and interpreter works with u32.
1907        let type_spec = vec![
1908            GlobalVariableTypeSpec::new(
1909                "request",
1910                Path::from_elems(vec!["path"]),
1911                InferredType::string(),
1912            ),
1913            GlobalVariableTypeSpec::new(
1914                "request",
1915                Path::from_elems(vec!["headers"]),
1916                InferredType::string(),
1917            ),
1918        ];
1919
1920        let mut rib_input = HashMap::new();
1921
1922        // We pass the input value to rib-interpreter with request.path.user-id
1923        // and request.headers.age as u32, since the compiler inferred these input type requirements to be u32.
1924        let analysed_type_of_input = &record(vec![
1925            field("path", record(vec![field("user-id", u32())])),
1926            field(
1927                "headers",
1928                record(vec![field("name", str()), field("age", u32())]),
1929            ),
1930        ]);
1931
1932        let value_and_type = get_value_and_type(
1933            analysed_type_of_input,
1934            r#"{path : { user-id: 1 }, headers: { name: "foo", age: 20 }}"#,
1935        );
1936
1937        rib_input.insert("request".to_string(), value_and_type);
1938
1939        let mut interpreter =
1940            test_utils::interpreter_with_noop_function_invoke(Some(RibInput::new(rib_input)));
1941
1942        let expr = Expr::from_text(rib_expr).unwrap();
1943
1944        let compiler = RibCompiler::new(RibCompilerConfig::new(
1945            ComponentDependency::default(),
1946            type_spec,
1947            vec![],
1948        ));
1949
1950        let compiled = compiler.compile(expr).unwrap();
1951
1952        let result = interpreter
1953            .run(compiled.byte_code)
1954            .await
1955            .unwrap()
1956            .get_val()
1957            .unwrap()
1958            .value;
1959
1960        assert_eq!(result, Value::String("21-foo".to_string()))
1961    }
1962
1963    #[test]
1964    async fn interpreter_concatenation() {
1965        let mut interpreter = Interpreter::default();
1966
1967        let rib_expr = r#"
1968            let x = "foo";
1969            let y = "bar";
1970            let z = {foo: "baz"};
1971            let n: u32 = 42;
1972            let result = "${x}-${y}-${z}-${n}";
1973            result
1974        "#;
1975
1976        let expr = Expr::from_text(rib_expr).unwrap();
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        assert_eq!(
1985            result.get_val().unwrap().value,
1986            Value::String("foo-bar-{foo: \"baz\"}-42".to_string())
1987        );
1988    }
1989
1990    #[test]
1991    async fn interpreter_with_variant_and_enum() {
1992        let test_deps = RibTestDeps::test_deps_with_global_functions();
1993
1994        let compiler = RibCompiler::new(RibCompilerConfig::new(
1995            test_deps.component.clone(),
1996            vec![],
1997            vec![],
1998        ));
1999
2000        let mut interpreter = test_deps.interpreter;
2001
2002        // This has intentionally got conflicting variable names
2003        // variable `x` is same as the enum name `x`
2004        // similarly, variably `validate` is same as the variant name validate
2005        let expr = r#"
2006          let x = x;
2007          let y = x;
2008          let a = instance();
2009          let result1 = a.add-enum(x, y);
2010          let validate = validate;
2011          let validate2 = validate;
2012          let result2 = a.add-variant(validate, validate2);
2013          {res1: result1, res2: result2}
2014        "#;
2015
2016        let expr = Expr::from_text(expr).unwrap();
2017
2018        let compiled = compiler.compile(expr);
2019
2020        let result = interpreter.run(compiled.unwrap().byte_code).await.unwrap();
2021        let expected_enum_type = r#enum(&["x", "y", "z"]);
2022        let expected_variant_type = get_analysed_type_variant();
2023
2024        let expected_record_type = record(vec![
2025            field("res1", expected_enum_type),
2026            field("res2", expected_variant_type),
2027        ]);
2028
2029        let expected_record_value = Value::Record(vec![
2030            Value::Enum(0),
2031            Value::Variant {
2032                case_idx: 2,
2033                case_value: None,
2034            },
2035        ]);
2036
2037        assert_eq!(
2038            result,
2039            RibResult::Val(ValueAndType::new(
2040                expected_record_value,
2041                expected_record_type
2042            ))
2043        );
2044    }
2045
2046    #[test]
2047    async fn interpreter_with_conflicting_variable_names() {
2048        let test_deps = RibTestDeps::test_deps_with_global_functions();
2049
2050        let compiler = RibCompiler::new(RibCompilerConfig::new(
2051            test_deps.component.clone(),
2052            vec![],
2053            vec![],
2054        ));
2055
2056        let mut interpreter = test_deps.interpreter;
2057
2058        // This has intentionally conflicting variable names
2059        // variable `x` is same as the enum name `x`
2060        // similarly, variably `validate` is same as the variant name `validate`
2061        // and `process-user` is same as the variant name `process-user`
2062        let expr = r#"
2063          let x = 1;
2064          let y = 2;
2065          let a = instance();
2066          let result1 = a.add-u32(x, y);
2067          let process-user = 3;
2068          let validate = 4;
2069          let result2 = a.add-u64(process-user, validate);
2070          {res1: result1, res2: result2}
2071        "#;
2072
2073        let expr = Expr::from_text(expr).unwrap();
2074
2075        let compiled = compiler.compile(expr).unwrap();
2076        let result = interpreter.run(compiled.byte_code).await.unwrap();
2077        let expected_value = Value::Record(vec![3u32.into_value(), 7u64.into_value()]);
2078
2079        let expected_type = record(vec![field("res1", u32()), field("res2", u64())]);
2080        assert_eq!(
2081            result,
2082            RibResult::Val(ValueAndType::new(expected_value, expected_type))
2083        );
2084    }
2085
2086    #[test]
2087    async fn interpreter_list_reduce() {
2088        let mut interpreter = Interpreter::default();
2089
2090        let rib_expr = r#"
2091          let x: list<u8> = [1, 2];
2092
2093          reduce z, a in x from 0u8 {
2094            yield z + a;
2095          }
2096
2097          "#;
2098
2099        let expr = Expr::from_text(rib_expr).unwrap();
2100        let compiler = RibCompiler::default();
2101        let compiled = compiler.compile(expr).unwrap();
2102        let result = interpreter
2103            .run(compiled.byte_code)
2104            .await
2105            .unwrap()
2106            .get_val()
2107            .unwrap();
2108
2109        assert_eq!(result, 3u8.into_value_and_type());
2110    }
2111
2112    #[test]
2113    async fn interpreter_list_reduce_from_record() {
2114        let mut interpreter = Interpreter::default();
2115
2116        let rib_expr = r#"
2117           let x = [{name: "foo", age: 1u64}, {name: "bar", age: 2u64}];
2118
2119           let names = for i in x {
2120             yield i.name;
2121           };
2122
2123          reduce z, a in names from "" {
2124            let result = if z == "" then a else "${z}, ${a}";
2125
2126            yield result;
2127          }
2128
2129          "#;
2130
2131        let expr = Expr::from_text(rib_expr).unwrap();
2132
2133        let compiler = RibCompiler::default();
2134        let compiled = compiler.compile(expr).unwrap();
2135
2136        let result = interpreter
2137            .run(compiled.byte_code)
2138            .await
2139            .unwrap()
2140            .get_val()
2141            .unwrap();
2142
2143        assert_eq!(result, "foo, bar".into_value_and_type());
2144    }
2145
2146    #[test]
2147    async fn interpreter_list_reduce_text() {
2148        let mut interpreter = Interpreter::default();
2149
2150        let rib_expr = r#"
2151           let x = ["foo", "bar"];
2152
2153          reduce z, a in x from "" {
2154            let result = if z == "" then a else "${z}, ${a}";
2155
2156            yield result;
2157          }
2158
2159          "#;
2160
2161        let expr = Expr::from_text(rib_expr).unwrap();
2162
2163        let compiler = RibCompiler::default();
2164
2165        let compiled = compiler.compile(expr).unwrap();
2166
2167        let result = interpreter
2168            .run(compiled.byte_code)
2169            .await
2170            .unwrap()
2171            .get_val()
2172            .unwrap();
2173
2174        assert_eq!(result, "foo, bar".into_value_and_type());
2175    }
2176
2177    #[test]
2178    async fn interpreter_list_reduce_empty() {
2179        let mut interpreter = Interpreter::default();
2180
2181        let rib_expr = r#"
2182          let x: list<u8> = [];
2183
2184          reduce z, a in x from 0u8 {
2185            yield z + a;
2186          }
2187
2188          "#;
2189
2190        let expr = Expr::from_text(rib_expr).unwrap();
2191
2192        let compiler = RibCompiler::default();
2193
2194        let compiled = compiler.compile(expr).unwrap();
2195
2196        let result = interpreter
2197            .run(compiled.byte_code)
2198            .await
2199            .unwrap()
2200            .get_val()
2201            .unwrap();
2202
2203        assert_eq!(result, 0u8.into_value_and_type());
2204    }
2205
2206    #[test]
2207    async fn interpreter_u32_parameter_inference_from_untyped_integer_expressions() {
2208        let ribs = [
2209            r#"
2210          let worker = instance("my-worker");
2211          worker.foo(1)
2212        "#,
2213            r#"
2214          let worker = instance("my-worker");
2215          let z = 1 + 2;
2216          worker.foo(z)
2217        "#,
2218        ];
2219
2220        for rib in ribs {
2221            let component_metadata =
2222                test_utils::configurable_metadata("foo", vec![u32()], Some(u64()));
2223            let mut interpreter = test_utils::interpreter_with_static_function_response(
2224                &ValueAndType::new(Value::U64(2), u64()),
2225                None,
2226            );
2227            let expr = Expr::from_text(rib).unwrap();
2228            let compiler =
2229                RibCompiler::new(RibCompilerConfig::new(component_metadata, vec![], vec![]));
2230            let compiled = compiler.compile(expr).unwrap();
2231            let result = interpreter.run(compiled.byte_code).await.unwrap();
2232            assert_eq!(
2233                result.get_val().unwrap(),
2234                ValueAndType::new(Value::U64(2), u64())
2235            );
2236        }
2237    }
2238
2239    #[test]
2240    async fn interpreter_rejects_u8_addition_feeding_u32_worker_parameter() {
2241        let ribs = [
2242            r#"
2243          let worker = instance("my-worker");
2244          let z = 1: u8 + 2;
2245          worker.foo(z)
2246        "#,
2247            r#"
2248          let worker = instance("my-worker");
2249          let z = 1: u8 + 2: u8;
2250          worker.foo(z)
2251        "#,
2252        ];
2253
2254        for rib in ribs {
2255            let component_metadata =
2256                test_utils::configurable_metadata("foo", vec![u32()], Some(u64()));
2257            let expr = Expr::from_text(rib).unwrap();
2258            let compiler =
2259                RibCompiler::new(RibCompilerConfig::new(component_metadata, vec![], vec![]));
2260            assert!(compiler.compile(expr).is_err());
2261        }
2262    }
2263
2264    #[test]
2265    async fn interpreter_list_comprehension_over_string_lists() {
2266        let cases = [
2267            (
2268                r#"
2269          let x = ["foo", "bar"];
2270
2271          for i in x {
2272            yield i;
2273          }
2274          "#,
2275                r#"["foo", "bar"]"#,
2276            ),
2277            (
2278                r#"
2279          let x: list<string> = [];
2280
2281          for i in x {
2282            yield i;
2283          }
2284          "#,
2285                r#"[]"#,
2286            ),
2287        ];
2288
2289        for (rib_expr, expected_wave) in cases {
2290            let mut interpreter = Interpreter::default();
2291            let expr = Expr::from_text(rib_expr).unwrap();
2292            let compiler = RibCompiler::default();
2293            let compiled = compiler.compile(expr).unwrap();
2294            let result = interpreter
2295                .run(compiled.byte_code)
2296                .await
2297                .unwrap()
2298                .get_val()
2299                .unwrap();
2300            let expected = crate::parse_value_and_type(&list(str()), expected_wave).unwrap();
2301            assert_eq!(result, expected);
2302        }
2303    }
2304
2305    #[test]
2306    async fn interpreter_pattern_match_on_option_nested() {
2307        let mut interpreter = Interpreter::default();
2308
2309        let expr = r#"
2310           let x: option<option<u64>> = none;
2311
2312           match x {
2313              some(some(t)) => t,
2314              some(none) => 0u64,
2315              none => 0u64
2316
2317           }
2318        "#;
2319
2320        let expr = Expr::from_text(expr).unwrap();
2321        let compiler = RibCompiler::default();
2322        let compiled = compiler.compile(expr).unwrap();
2323        let result = interpreter.run(compiled.byte_code).await.unwrap();
2324
2325        assert_eq!(result.get_val().unwrap(), 0u64.into_value_and_type());
2326    }
2327
2328    #[test]
2329    async fn interpreter_pattern_match_on_tuple() {
2330        let mut interpreter = Interpreter::default();
2331
2332        let expr = r#"
2333           let x: tuple<u64, string, string> = (1, "foo", "bar");
2334
2335           match x {
2336              (x, y, z) => "${x} ${y} ${z}"
2337           }
2338        "#;
2339
2340        let expr = Expr::from_text(expr).unwrap();
2341        let compiler = RibCompiler::default();
2342        let compiled = compiler.compile(expr).unwrap();
2343        let result = interpreter.run(compiled.byte_code).await.unwrap();
2344
2345        assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type());
2346    }
2347
2348    #[test]
2349    async fn interpreter_pattern_match_on_tuple_with_option_some() {
2350        let mut interpreter = Interpreter::default();
2351
2352        let expr = r#"
2353           let x: tuple<u64, option<string>, string> = (1, some("foo"), "bar");
2354
2355           match x {
2356              (x, none, z) => "${x} ${z}",
2357              (x, some(y), z) => "${x} ${y} ${z}"
2358           }
2359        "#;
2360
2361        let expr = Expr::from_text(expr).unwrap();
2362        let compiler = RibCompiler::default();
2363        let compiled = compiler.compile(expr).unwrap();
2364        let result = interpreter.run(compiled.byte_code).await.unwrap();
2365
2366        assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type());
2367    }
2368
2369    #[test]
2370    async fn interpreter_pattern_match_on_tuple_with_option_none() {
2371        let mut interpreter = Interpreter::default();
2372
2373        let expr = r#"
2374           let x: tuple<u64, option<string>, string> = (1, none, "bar");
2375
2376           match x {
2377              (x, none, z) => "${x} ${z}",
2378              (x, some(y), z) => "${x} ${y} ${z}"
2379           }
2380        "#;
2381
2382        let expr = Expr::from_text(expr).unwrap();
2383        let compiler = RibCompiler::default();
2384        let compiled = compiler.compile(expr).unwrap();
2385        let result = interpreter.run(compiled.byte_code).await.unwrap();
2386
2387        assert_eq!(result.get_val().unwrap(), "1 bar".into_value_and_type());
2388    }
2389
2390    #[test]
2391    async fn interpreter_pattern_match_dynamic_branch_1() {
2392        let mut interpreter = Interpreter::default();
2393
2394        let expr = r#"
2395           let x = 1;
2396
2397           match x {
2398                1 => ok(1),
2399                2 => err("none")
2400           }
2401        "#;
2402
2403        let expr = Expr::from_text(expr).unwrap();
2404        let compiler = RibCompiler::default();
2405        let compiled = compiler.compile(expr).unwrap();
2406        let rib_result = interpreter.run(compiled.byte_code).await.unwrap();
2407
2408        let expected = ValueAndType::new(
2409            Value::Result(Ok(Some(Box::new(Value::S32(1))))),
2410            result(s32(), str()),
2411        );
2412
2413        assert_eq!(rib_result.get_val().unwrap(), expected);
2414    }
2415
2416    #[test]
2417    async fn interpreter_pattern_match_dynamic_branch_2() {
2418        let mut interpreter = Interpreter::default();
2419
2420        let expr = r#"
2421           let x = some({foo: 1});
2422
2423           match x {
2424               some(x) => ok(x.foo),
2425               none => err("none")
2426           }
2427        "#;
2428
2429        let expr = Expr::from_text(expr).unwrap();
2430        let compiler = RibCompiler::default();
2431        let compiled = compiler.compile(expr).unwrap();
2432        let rib_result = interpreter.run(compiled.byte_code).await.unwrap();
2433
2434        let expected = ValueAndType::new(
2435            Value::Result(Ok(Some(Box::new(Value::S32(1))))),
2436            result(s32(), str()),
2437        );
2438
2439        assert_eq!(rib_result.get_val().unwrap(), expected);
2440    }
2441
2442    #[test]
2443    async fn interpreter_pattern_match_on_tuple_with_all_types() {
2444        let mut interpreter = Interpreter::default();
2445
2446        let tuple = test_utils::get_analysed_type_tuple();
2447
2448        let analysed_exports = test_utils::configurable_metadata("foo", vec![tuple], Some(str()));
2449
2450        let expr = r#"
2451           let worker = instance();
2452           let record = { request : { path : { user : "jak" } }, y : "bar" };
2453           let input = (1, ok(100), "bar", record, process-user("jon"), register-user(1u64), validate, prod, dev, test);
2454           worker.foo(input);
2455           match input {
2456             (n1, err(x1), txt, rec, process-user(x), register-user(n), validate, dev, prod, test) =>  "Invalid",
2457             (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}"
2458           }
2459
2460        "#;
2461
2462        let expr = Expr::from_text(expr).unwrap();
2463        let compiler = RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
2464        let compiled = compiler.compile(expr).unwrap();
2465        let result = interpreter.run(compiled.byte_code).await.unwrap();
2466
2467        assert_eq!(
2468            result.get_val().unwrap(),
2469            "foo 100 1 bar jak validate prod dev test".into_value_and_type()
2470        );
2471    }
2472
2473    #[test]
2474    async fn interpreter_pattern_match_on_tuple_with_wild_pattern() {
2475        let mut interpreter = Interpreter::default();
2476
2477        let tuple = test_utils::get_analysed_type_tuple();
2478
2479        let analysed_exports =
2480            test_utils::configurable_metadata("my-worker-function", vec![tuple], Some(str()));
2481
2482        let expr = r#"
2483           let worker = instance();
2484           let record = { request : { path : { user : "jak" } }, y : "baz" };
2485           let input = (1, ok(1), "bar", record, process-user("jon"), register-user(1u64), validate, prod, dev, test);
2486           worker.my-worker-function(input);
2487           match input {
2488             (n1, ok(x), txt, rec, _, _, _, _, prod, _) =>  "prod ${n1} ${txt} ${rec.request.path.user} ${rec.y}",
2489             (n1, ok(x), txt, rec, _, _, _, _, dev, _) =>   "dev ${n1} ${txt} ${rec.request.path.user} ${rec.y}"
2490           }
2491        "#;
2492
2493        let expr = Expr::from_text(expr).unwrap();
2494        let compiler = RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
2495        let compiled = compiler.compile(expr).unwrap();
2496        let result = interpreter.run(compiled.byte_code).await.unwrap();
2497
2498        assert_eq!(
2499            result.get_val().unwrap(),
2500            "dev 1 bar jak baz".into_value_and_type()
2501        );
2502    }
2503
2504    #[test]
2505    async fn interpreter_record_output_in_pattern_match() {
2506        let input_analysed_type = test_utils::get_analysed_type_record();
2507        let output_analysed_type = test_utils::get_analysed_type_result();
2508
2509        let result_value = get_value_and_type(&output_analysed_type, r#"ok(1)"#);
2510
2511        let mut interpreter =
2512            test_utils::interpreter_with_static_function_response(&result_value, None);
2513
2514        let analysed_exports = test_utils::configurable_metadata(
2515            "my-worker-function",
2516            vec![input_analysed_type],
2517            Some(output_analysed_type),
2518        );
2519
2520        let expr = r#"
2521           let worker = instance();
2522           let input = { request : { path : { user : "jak" } }, y : "baz" };
2523           let result = worker.my-worker-function(input);
2524           match result {
2525             ok(result) => { body: result, status: 200 },
2526             err(result) => { status: 400, body: 400 }
2527           }
2528        "#;
2529
2530        let expr = Expr::from_text(expr).unwrap();
2531        let compiler = RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
2532        let compiled = compiler.compile(expr).unwrap();
2533        let result = interpreter.run(compiled.byte_code).await.unwrap();
2534
2535        let expected = test_utils::get_value_and_type(
2536            &record(vec![field("body", u64()), field("status", s32())]),
2537            r#"{body: 1, status: 200}"#,
2538        );
2539
2540        assert_eq!(result.get_val().unwrap(), expected);
2541    }
2542
2543    #[test]
2544    async fn interpreter_tuple_output_in_pattern_match() {
2545        let input_analysed_type = test_utils::get_analysed_type_record();
2546        let output_analysed_type = test_utils::get_analysed_type_result();
2547
2548        let result_value = get_value_and_type(&output_analysed_type, r#"err("failed")"#);
2549
2550        let mut interpreter =
2551            test_utils::interpreter_with_static_function_response(&result_value, None);
2552
2553        let analysed_exports = test_utils::configurable_metadata(
2554            "my-worker-function",
2555            vec![input_analysed_type],
2556            Some(output_analysed_type),
2557        );
2558
2559        let expr = r#"
2560           let input = { request : { path : { user : "jak" } }, y : "baz" };
2561           let worker = instance();
2562           let result = worker.my-worker-function(input);
2563           match result {
2564             ok(res) => ("${res}", "foo"),
2565             err(msg) => (msg, "bar")
2566           }
2567        "#;
2568
2569        let expr = Expr::from_text(expr).unwrap();
2570        let compiler = RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
2571        let compiled = compiler.compile(expr).unwrap();
2572        let result = interpreter.run(compiled.byte_code).await.unwrap();
2573
2574        let expected = get_value_and_type(&tuple(vec![str(), str()]), r#"("failed", "bar")"#);
2575
2576        assert_eq!(result.get_val().unwrap(), expected);
2577    }
2578
2579    #[test]
2580    async fn interpreter_with_indexed_resource_drop() {
2581        let expr = r#"
2582           let user_id = "user";
2583           let worker = instance();
2584           let cart = worker.cart(user_id);
2585           cart.drop();
2586           "success"
2587        "#;
2588        let expr = Expr::from_text(expr).unwrap();
2589        let component_metadata = test_utils::get_metadata_with_resource_with_params();
2590
2591        let compiler_config = RibCompilerConfig::new(component_metadata, vec![], vec![]);
2592        let compiler = RibCompiler::new(compiler_config);
2593        let compiled = compiler.compile(expr).unwrap();
2594
2595        let mut rib_interpreter = test_utils::interpreter_with_resource_function_invoke_impl(None);
2596        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
2597
2598        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
2599    }
2600
2601    #[test]
2602    async fn interpreter_with_indexed_resource_checkout() {
2603        let expr = r#"
2604           let user_id = "foo";
2605           let worker = instance();
2606           let cart = worker.cart(user_id);
2607           let result = cart.checkout();
2608           result
2609        "#;
2610
2611        let expr = Expr::from_text(expr).unwrap();
2612
2613        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2614
2615        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2616        let compiler = RibCompiler::new(compiler_config);
2617
2618        let compiled = compiler.compile(expr).unwrap();
2619
2620        let mut rib_executor = test_deps.interpreter;
2621        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2622
2623        let expected_value = Value::Variant {
2624            case_idx: 1,
2625            case_value: Some(Box::new(Value::Record(vec![Value::String(
2626                "foo".to_string(),
2627            )]))),
2628        };
2629
2630        assert_eq!(result.get_val().unwrap().value, expected_value);
2631    }
2632
2633    #[test]
2634    async fn interpreter_with_indexed_resources_static_functions_1() {
2635        let expr = r#"
2636           let worker = instance();
2637           let result = worker.cart.create("afsal");
2638           result.checkout()
2639        "#;
2640
2641        let expr = Expr::from_text(expr).unwrap();
2642
2643        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2644
2645        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2646        let compiler = RibCompiler::new(compiler_config);
2647
2648        let compiled = compiler.compile(expr).unwrap();
2649
2650        let mut rib_executor = test_deps.interpreter;
2651        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2652
2653        let expected_value = Value::Variant {
2654            case_idx: 1,
2655            case_value: Some(Box::new(Value::Record(vec![Value::String(
2656                "foo".to_string(),
2657            )]))),
2658        };
2659
2660        assert_eq!(result.get_val().unwrap().value, expected_value);
2661    }
2662
2663    #[test]
2664    async fn interpreter_with_indexed_resources_static_functions_2() {
2665        let expr = r#"
2666           let worker = instance();
2667           let default-cart = worker.cart("default");
2668           let alternate-cart = worker.cart.create-safe("afsal");
2669           match alternate-cart {
2670             ok(alt) => alt.checkout(),
2671             err(_) => default-cart.checkout()
2672           }
2673        "#;
2674
2675        let expr = Expr::from_text(expr).unwrap();
2676
2677        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2678
2679        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2680        let compiler = RibCompiler::new(compiler_config);
2681
2682        let compiled = compiler.compile(expr).unwrap();
2683
2684        let mut rib_executor = test_deps.interpreter;
2685        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2686
2687        let expected_value = Value::Variant {
2688            case_idx: 1,
2689            case_value: Some(Box::new(Value::Record(vec![Value::String(
2690                "foo".to_string(),
2691            )]))),
2692        };
2693
2694        assert_eq!(result.get_val().unwrap().value, expected_value);
2695    }
2696
2697    #[test]
2698    async fn interpreter_with_indexed_resource_get_cart_contents() {
2699        let expr = r#"
2700           let user_id = "bar";
2701           let worker = instance();
2702           let cart = worker.cart(user_id);
2703           let result = cart.get-cart-contents();
2704           result[0].product-id
2705        "#;
2706
2707        let expr = Expr::from_text(expr).unwrap();
2708
2709        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2710
2711        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2712        let compiler = RibCompiler::new(compiler_config);
2713
2714        let compiled = compiler.compile(expr).unwrap();
2715
2716        let mut rib_executor = test_deps.interpreter;
2717
2718        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2719
2720        assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type());
2721    }
2722
2723    #[test]
2724    async fn interpreter_with_indexed_resource_update_item_quantity() {
2725        let expr = r#"
2726           let user_id = "jon";
2727           let product_id = "mac";
2728           let quantity = 1032;
2729           let worker = instance();
2730           let cart = worker.cart(user_id);
2731           cart.update-item-quantity(product_id, quantity);
2732           "successfully updated"
2733        "#;
2734        let expr = Expr::from_text(expr).unwrap();
2735
2736        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2737
2738        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2739        let compiler = RibCompiler::new(compiler_config);
2740
2741        let compiled = compiler.compile(expr).unwrap();
2742
2743        let mut rib_executor = test_deps.interpreter;
2744
2745        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2746
2747        assert_eq!(
2748            result.get_val().unwrap(),
2749            "successfully updated".into_value_and_type()
2750        );
2751    }
2752
2753    #[test]
2754    async fn interpreter_with_indexed_resource_add_item() {
2755        let expr = r#"
2756           let user_id = "foo";
2757           let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 };
2758           let worker = instance();
2759           let cart = worker.cart(user_id);
2760           cart.add-item(product);
2761
2762           "successfully added"
2763        "#;
2764
2765        let expr = Expr::from_text(expr).unwrap();
2766
2767        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
2768
2769        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2770        let compiler = RibCompiler::new(compiler_config);
2771
2772        let compiled = compiler.compile(expr).unwrap();
2773
2774        let mut rib_executor = test_deps.interpreter;
2775
2776        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2777
2778        assert_eq!(
2779            result.get_val().unwrap(),
2780            "successfully added".into_value_and_type()
2781        );
2782    }
2783
2784    #[test]
2785    async fn interpreter_with_resource_add_item() {
2786        let expr = r#"
2787           let worker = instance();
2788           let cart = worker.cart();
2789           let user_id = "foo";
2790           let product = { product-id: "mac", name: "macbook", quantity: 1u32, price: 1f32 };
2791           cart.add-item(product);
2792
2793           "successfully added"
2794        "#;
2795
2796        let expr = Expr::from_text(expr).unwrap();
2797
2798        let test_deps = RibTestDeps::test_deps_with_resource_functions(None);
2799
2800        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2801        let compiler = RibCompiler::new(compiler_config);
2802
2803        let compiled = compiler.compile(expr).unwrap();
2804
2805        let mut rib_executor = test_deps.interpreter;
2806
2807        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2808
2809        assert_eq!(
2810            result.get_val().unwrap(),
2811            "successfully added".into_value_and_type()
2812        );
2813    }
2814
2815    #[test]
2816    async fn interpreter_with_resource_get_cart_contents() {
2817        let expr = r#"
2818           let worker = instance();
2819           let cart = worker.cart();
2820           let result = cart.get-cart-contents();
2821           result[0].product-id
2822        "#;
2823
2824        let expr = Expr::from_text(expr).unwrap();
2825
2826        let test_deps = RibTestDeps::test_deps_with_resource_functions(None);
2827
2828        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2829        let compiler = RibCompiler::new(compiler_config);
2830
2831        let compiled = compiler.compile(expr).unwrap();
2832
2833        let mut rib_executor = test_deps.interpreter;
2834        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2835
2836        assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type());
2837    }
2838
2839    #[test]
2840    async fn interpreter_with_resource_update_item() {
2841        let expr = r#"
2842           let worker = instance();
2843           let product_id = "mac";
2844           let quantity = 1032;
2845           let cart = worker.cart();
2846           cart.update-item-quantity(product_id, quantity);
2847           "successfully updated"
2848        "#;
2849        let expr = Expr::from_text(expr).unwrap();
2850
2851        let test_deps = RibTestDeps::test_deps_with_resource_functions(None);
2852
2853        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2854        let compiler = RibCompiler::new(compiler_config);
2855
2856        let compiled = compiler.compile(expr).unwrap();
2857
2858        let mut rib_executor = test_deps.interpreter;
2859
2860        let result = rib_executor.run(compiled.byte_code).await.unwrap();
2861
2862        assert_eq!(
2863            result.get_val().unwrap(),
2864            "successfully updated".into_value_and_type()
2865        );
2866    }
2867
2868    #[test]
2869    async fn interpreter_with_resource_checkout() {
2870        let expr = r#"
2871           let worker = instance();
2872           let cart = worker.cart();
2873           let result = cart.checkout();
2874           result
2875        "#;
2876
2877        let expr = Expr::from_text(expr).unwrap();
2878
2879        let test_deps = RibTestDeps::test_deps_with_resource_functions(None);
2880
2881        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2882
2883        let compiler = RibCompiler::new(compiler_config);
2884
2885        let compiled = compiler.compile(expr).unwrap();
2886
2887        let mut interpreter = test_deps.interpreter;
2888
2889        let result = interpreter.run(compiled.byte_code).await.unwrap();
2890
2891        let expected_result = Value::Variant {
2892            case_idx: 1,
2893            case_value: Some(Box::new(Value::Record(vec![Value::String(
2894                "foo".to_string(),
2895            )]))),
2896        };
2897
2898        assert_eq!(result.get_val().unwrap().value, expected_result);
2899    }
2900
2901    #[test]
2902    async fn interpreter_with_resource_drop() {
2903        let expr = r#"
2904           let worker = instance();
2905           let cart = worker.cart();
2906           cart.drop();
2907           "success"
2908        "#;
2909        let expr = Expr::from_text(expr).unwrap();
2910        let test_deps = RibTestDeps::test_deps_with_resource_functions(None);
2911
2912        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
2913        let compiler = RibCompiler::new(compiler_config);
2914        let compiled = compiler.compile(expr).unwrap();
2915
2916        let mut rib_interpreter = test_deps.interpreter;
2917        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
2918
2919        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
2920    }
2921
2922    /// `list[1..]` slicing is allowed; unbounded `for i in 1..` is rejected elsewhere.
2923    #[test]
2924    async fn interpreter_list_dynamic_index_slice_and_reduce() {
2925        enum Expect {
2926            Ok(ValueAndType),
2927            Err(&'static str),
2928        }
2929
2930        let cases: Vec<(&str, Expect)> = vec![
2931            (
2932                r#"
2933              let list: list<u8> = [1, 2, 3, 4, 5];
2934              let index: u8 = 4;
2935              list[index]
2936              "#,
2937                Expect::Ok(ValueAndType::new(Value::U8(5), u8())),
2938            ),
2939            (
2940                r#"
2941              let list: list<u8> = [1, 2, 3, 4, 5];
2942              let index: u8 = 10;
2943              list[index]
2944              "#,
2945                Expect::Err("index out of bound: 10 (size: 5)"),
2946            ),
2947            (
2948                r#"
2949              let list: list<u8> = [1, 2, 3, 4, 5];
2950              let indices: list<u8> = [0, 1, 2, 3];
2951
2952              for i in indices {
2953                 yield list[i];
2954              }
2955              "#,
2956                Expect::Ok(ValueAndType::new(
2957                    Value::List(vec![Value::U8(1), Value::U8(2), Value::U8(3), Value::U8(4)]),
2958                    list(u8()),
2959                )),
2960            ),
2961            (
2962                r#"
2963              let list: list<u8> = [2, 5, 4];
2964              let indices: list<u8> = [0, 1];
2965
2966               reduce z, index in indices from 0u8 {
2967                  yield list[index] + z;
2968                }
2969              "#,
2970                Expect::Ok(ValueAndType::new(Value::U8(7), u8())),
2971            ),
2972            (
2973                r#"
2974              let list: list<u8> = [2, 5, 4];
2975              let x: u8 = 0;
2976              let y: u8 = 2;
2977              list[x..=y]
2978              "#,
2979                Expect::Ok(ValueAndType::new(
2980                    Value::List(vec![Value::U8(2), Value::U8(5), Value::U8(4)]),
2981                    list(u8()),
2982                )),
2983            ),
2984            (
2985                r#"
2986              let list: list<u8> = [2, 5, 4];
2987              let x: u8 = 0;
2988              let y: u8 = 2;
2989              let x1: u8 = 1;
2990              let result = list[x..=y];
2991              for i in result[x1..=y] {
2992                yield i;
2993              }
2994              "#,
2995                Expect::Ok(ValueAndType::new(
2996                    Value::List(vec![Value::U8(5), Value::U8(4)]),
2997                    list(u8()),
2998                )),
2999            ),
3000            (
3001                r#"
3002              let list: list<u8> = [2, 5, 4, 6];
3003              let x: u8 = 0;
3004              let y: u8 = 2;
3005              let result = list[x..y];
3006              for i in result[x..y] {
3007                yield i;
3008              }
3009              "#,
3010                Expect::Ok(ValueAndType::new(
3011                    Value::List(vec![Value::U8(2), Value::U8(5)]),
3012                    list(u8()),
3013                )),
3014            ),
3015            (
3016                r#"
3017              let list: list<u8> = [2, 5, 4, 6];
3018              let x: u8 = 0;
3019              let result = list[x..];
3020              for i in result[x..] {
3021                yield i;
3022              }
3023              "#,
3024                Expect::Ok(ValueAndType::new(
3025                    Value::List(vec![Value::U8(2), Value::U8(5)]),
3026                    list(u8()),
3027                )),
3028            ),
3029            (
3030                r#"
3031              let list: list<u8> = [2, 5, 4, 6];
3032              let result = list[0..2];
3033              for i in result[0..2] {
3034                yield i;
3035              }
3036              "#,
3037                Expect::Ok(ValueAndType::new(
3038                    Value::List(vec![Value::U8(2), Value::U8(5)]),
3039                    list(u8()),
3040                )),
3041            ),
3042        ];
3043
3044        for (rib, expect) in cases {
3045            let expr = Expr::from_text(rib).unwrap();
3046            let compiler = RibCompiler::default();
3047            let compiled = compiler.compile(expr).unwrap();
3048            let mut interpreter = Interpreter::default();
3049            match expect {
3050                Expect::Ok(expected) => {
3051                    let result = interpreter.run(compiled.byte_code).await.unwrap();
3052                    assert_eq!(result.get_val().unwrap(), expected);
3053                }
3054                Expect::Err(msg) => {
3055                    let err = interpreter.run(compiled.byte_code).await.unwrap_err();
3056                    assert_eq!(err.to_string(), msg);
3057                }
3058            }
3059        }
3060    }
3061
3062    /// Range values are records (`from` / optional `to` / `inclusive`), not evaluated spans.
3063    #[test]
3064    async fn interpreter_range_literals_are_typed_records() {
3065        let cases: Vec<(&str, ValueAndType)> = vec![
3066            (
3067                r#"
3068              let x = 1..;
3069              x
3070              "#,
3071                ValueAndType::new(
3072                    Value::Record(vec![Value::S32(1), Value::Bool(false)]),
3073                    record(vec![field("from", s32()), field("inclusive", bool())]),
3074                ),
3075            ),
3076            (
3077                r#"
3078              let x = 1..2;
3079              x
3080              "#,
3081                ValueAndType::new(
3082                    Value::Record(vec![Value::S32(1), Value::S32(2), Value::Bool(false)]),
3083                    record(vec![
3084                        field("from", s32()),
3085                        field("to", s32()),
3086                        field("inclusive", bool()),
3087                    ]),
3088                ),
3089            ),
3090            (
3091                r#"
3092              let x = 1..=10;
3093              x
3094              "#,
3095                ValueAndType::new(
3096                    Value::Record(vec![Value::S32(1), Value::S32(10), Value::Bool(true)]),
3097                    record(vec![
3098                        field("from", s32()),
3099                        field("to", s32()),
3100                        field("inclusive", bool()),
3101                    ]),
3102                ),
3103            ),
3104            (
3105                r#"
3106              let x = 1:u64;
3107              let y = x;
3108              let range = x..=y;
3109              let range2 = x..;
3110              let range3 = x..y;
3111              range;
3112              range2;
3113              range3
3114              "#,
3115                ValueAndType::new(
3116                    Value::Record(vec![Value::U64(1), Value::U64(1), Value::Bool(false)]),
3117                    record(vec![
3118                        field("from", u64()),
3119                        field("to", u64()),
3120                        field("inclusive", bool()),
3121                    ]),
3122                ),
3123            ),
3124            (
3125                r#"
3126              let y = 1 + 10;
3127              1..y
3128              "#,
3129                ValueAndType::new(
3130                    Value::Record(vec![Value::S32(1), Value::S32(11), Value::Bool(false)]),
3131                    record(vec![
3132                        field("from", s32()),
3133                        field("to", s32()),
3134                        field("inclusive", bool()),
3135                    ]),
3136                ),
3137            ),
3138        ];
3139
3140        for (rib, expected) in cases {
3141            let expr = Expr::from_text(rib).unwrap();
3142            let compiler = RibCompiler::default();
3143            let compiled = compiler.compile(expr).unwrap();
3144            let mut interpreter = Interpreter::default();
3145            let result = interpreter.run(compiled.byte_code).await.unwrap();
3146            assert_eq!(result.get_val().unwrap(), expected);
3147        }
3148    }
3149
3150    #[test]
3151    async fn interpreter_list_comprehension_over_bounded_ranges() {
3152        let cases: Vec<(&str, Vec<Value>)> = vec![
3153            (
3154                r#"
3155              let range = 1..=5;
3156              for i in range {
3157                yield i;
3158              }
3159              "#,
3160                vec![
3161                    Value::S32(1),
3162                    Value::S32(2),
3163                    Value::S32(3),
3164                    Value::S32(4),
3165                    Value::S32(5),
3166                ],
3167            ),
3168            (
3169                r#"
3170              let range = 1..5;
3171              for i in range {
3172                yield i;
3173              }
3174              "#,
3175                vec![Value::S32(1), Value::S32(2), Value::S32(3), Value::S32(4)],
3176            ),
3177        ];
3178
3179        for (rib, items) in cases {
3180            let expr = Expr::from_text(rib).unwrap();
3181            let compiler = RibCompiler::default();
3182            let compiled = compiler.compile(expr).unwrap();
3183            let mut interpreter = Interpreter::default();
3184            let result = interpreter.run(compiled.byte_code).await.unwrap();
3185            let expected = ValueAndType::new(Value::List(items), list(s32()));
3186            assert_eq!(result.get_val().unwrap(), expected);
3187        }
3188    }
3189
3190    #[test]
3191    async fn interpreter_list_comprehension_rejects_unbounded_range() {
3192        let expr = r#"
3193              let range = 1..;
3194              for i in range {
3195                yield i;
3196              }
3197              "#;
3198
3199        let expr = Expr::from_text(expr).unwrap();
3200
3201        let compiler = RibCompiler::default();
3202        let compiled = compiler.compile(expr).unwrap();
3203
3204        let mut interpreter = Interpreter::default();
3205        let result = interpreter.run(compiled.byte_code).await;
3206        assert!(result.is_err());
3207    }
3208
3209    #[test]
3210    async fn interpreter_reduce_over_half_open_range() {
3211        let expr = r#"
3212                let initial = 1;
3213                let final = 5;
3214                let x = initial..final;
3215
3216                reduce z, a in x from 0u8 {
3217                  yield z + a;
3218                }
3219              "#;
3220
3221        let expr = Expr::from_text(expr).unwrap();
3222
3223        let compiler = RibCompiler::default();
3224        let compiled = compiler.compile(expr).unwrap();
3225
3226        let mut interpreter = Interpreter::default();
3227        let result = interpreter.run(compiled.byte_code).await.unwrap();
3228
3229        let expected = ValueAndType::new(Value::U8(10), u8());
3230
3231        assert_eq!(result.get_val().unwrap(), expected);
3232    }
3233
3234    #[test]
3235    async fn interpreter_ephemeral_pass_through_invocation() {
3236        let expr = r#"
3237              let x = instance();
3238              let result = x.pass-through(1, 2);
3239              result
3240            "#;
3241        let expr = Expr::from_text(expr).unwrap();
3242
3243        let test_deps = RibTestDeps::test_deps_for_pass_through_function();
3244
3245        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3246        let compiler = RibCompiler::new(compiler_config);
3247        let compiled = compiler.compile(expr).unwrap();
3248
3249        let mut rib_interpreter = test_deps.interpreter;
3250
3251        let result = rib_interpreter
3252            .run(compiled.byte_code)
3253            .await
3254            .unwrap()
3255            .get_val()
3256            .unwrap()
3257            .value;
3258
3259        let expected_value = Value::Record(vec![
3260            Value::String("test-worker".to_string()),
3261            Value::String("pass-through".to_string()),
3262            Value::U64(1),
3263            Value::U32(2),
3264        ]);
3265
3266        assert_eq!(result, expected_value)
3267    }
3268
3269    #[test]
3270    async fn interpreter_ephemeral_instance_binding_without_invocation_compiles() {
3271        let expr = r#"
3272              let x = instance();
3273              x
3274            "#;
3275        let expr = Expr::from_text(expr).unwrap();
3276
3277        let test_deps = RibTestDeps::test_deps_with_global_functions();
3278
3279        let compiler = RibCompiler::new(RibCompilerConfig::new(
3280            test_deps.component.clone(),
3281            vec![],
3282            vec![],
3283        ));
3284
3285        let compiled = compiler.compile(expr);
3286
3287        assert!(compiled.is_ok());
3288    }
3289
3290    #[test]
3291    async fn interpreter_bare_instance_keyword_rejected() {
3292        let expr = r#"
3293             instance
3294            "#;
3295        let expr = Expr::from_text(expr).unwrap();
3296
3297        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3298
3299        let compiler = RibCompiler::new(RibCompilerConfig::new(
3300            test_deps.component.clone(),
3301            vec![],
3302            vec![],
3303        ));
3304
3305        let compiled = compiler.compile(expr);
3306
3307        assert!(compiled.is_err());
3308    }
3309
3310    #[test]
3311    async fn interpreter_ephemeral_instance_call_with_multi_interface_metadata_compiles() {
3312        let expr = r#"
3313              instance()
3314            "#;
3315        let expr = Expr::from_text(expr).unwrap();
3316
3317        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3318
3319        let compiler = RibCompiler::new(RibCompilerConfig::new(
3320            test_deps.component.clone(),
3321            vec![],
3322            vec![],
3323        ));
3324
3325        let compiled = compiler.compile(expr);
3326
3327        assert!(compiled.is_ok());
3328    }
3329
3330    #[test]
3331    async fn interpreter_inline_call_on_instance_expression_rejected() {
3332        let expr = r#"
3333              let worker = instance().foo("bar")
3334            "#;
3335        let expr = Expr::from_text(expr).unwrap();
3336
3337        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3338
3339        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3340        let compiler = RibCompiler::new(compiler_config);
3341        let error = compiler.compile(expr).unwrap_err();
3342
3343        assert_eq!(
3344            error.to_string(),
3345            "inline invocation of functions on a worker instance is currently not supported"
3346        );
3347    }
3348
3349    #[test]
3350    async fn interpreter_reserved_instance_used_like_variable_errors_with_help() {
3351        let expr = r#"
3352              let result = instance.foo("bar");
3353              result
3354            "#;
3355        let expr = Expr::from_text(expr).unwrap();
3356        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3357
3358        let compiler = RibCompiler::new(RibCompilerConfig::new(
3359            test_deps.component.clone(),
3360            vec![],
3361            vec![],
3362        ));
3363
3364        let compiled = compiler.compile(expr).unwrap_err().to_string();
3365
3366        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());
3367    }
3368
3369    #[test]
3370    async fn interpreter_ambiguous_function_across_wit_interfaces_errors() {
3371        let expr = r#"
3372                let x = instance();
3373                let result = x.bar("bar");
3374                result
3375            "#;
3376        let expr = Expr::from_text(expr).unwrap();
3377        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3378
3379        let compiler = RibCompiler::new(RibCompilerConfig::new(
3380            test_deps.component.clone(),
3381            vec![],
3382            vec![],
3383        ));
3384
3385        let compilation_error = compiler.compile(expr).unwrap_err().to_string();
3386
3387        assert_eq!(
3388            compilation_error,
3389            "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'; disambiguate with a fully qualified WIT call (e.g. ns:pkg/interface.{fn}). interfaces: api1, api2\n".to_string()
3390        );
3391    }
3392
3393    #[test]
3394    async fn interpreter_loop_invokes_unambiguous_interface_function() {
3395        let expr = r#"
3396                let worker = instance();
3397                let invokes: list<u8> = [1, 2, 3, 4];
3398
3399                for i in invokes {
3400                    yield worker.baz("bar");
3401                };
3402
3403                "success"
3404            "#;
3405        let expr = Expr::from_text(expr).unwrap();
3406        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3407
3408        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3409        let compiler = RibCompiler::new(compiler_config);
3410        let compiled = compiler.compile(expr).unwrap();
3411
3412        let mut rib_interpreter = test_deps.interpreter;
3413
3414        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3415
3416        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3417    }
3418
3419    #[test]
3420    async fn interpreter_durable_named_worker_pass_through_invocation() {
3421        let expr = r#"
3422                let worker = instance("my-worker");
3423                let result = worker.pass-through(42, 43);
3424                result
3425            "#;
3426        let expr = Expr::from_text(expr).unwrap();
3427        let test_deps = RibTestDeps::test_deps_for_pass_through_function();
3428
3429        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3430        let compiler = RibCompiler::new(compiler_config);
3431        let compiled = compiler.compile(expr).unwrap();
3432
3433        let mut rib_interpreter = test_deps.interpreter;
3434
3435        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3436
3437        let expected_val = Value::Record(vec![
3438            Value::String("my-worker".to_string()),
3439            Value::String("pass-through".to_string()),
3440            Value::U64(42),
3441            Value::U32(43),
3442        ]);
3443
3444        assert_eq!(result.get_val().unwrap().value, expected_val);
3445    }
3446
3447    #[test]
3448    async fn interpreter_durable_worker_1_1() {
3449        let expr = r#"
3450                let x = 1;
3451                let y = 2;
3452                let inst = instance("my-worker");
3453                inst.foo-number(x, y)
3454            "#;
3455        let expr = Expr::from_text(expr).unwrap();
3456        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3457
3458        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3459        let compiler = RibCompiler::new(compiler_config);
3460        let compiled = compiler.compile(expr).unwrap();
3461
3462        let mut rib_interpreter = test_deps.interpreter;
3463
3464        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3465
3466        assert_eq!(result.get_val().unwrap().value, Value::S32(1));
3467    }
3468
3469    #[test]
3470    async fn interpreter_durable_worker_2() {
3471        let expr = r#"
3472                let inst = instance("my-worker");
3473                let result = inst.foo("bar");
3474                result
3475            "#;
3476        let expr = Expr::from_text(expr).unwrap();
3477        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3478
3479        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3480        let compiler = RibCompiler::new(compiler_config);
3481        let compiled = compiler.compile(expr).unwrap();
3482
3483        let mut rib_interpreter = test_deps.interpreter;
3484
3485        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3486
3487        assert_eq!(
3488            result.get_val().unwrap().value,
3489            Value::String("foo".to_string())
3490        );
3491    }
3492
3493    #[test]
3494    async fn interpreter_durable_worker_4() {
3495        let expr = r#"
3496                let worker = instance("my-worker");
3497                let result = worker.bar("bar");
3498                result
3499            "#;
3500        let expr = Expr::from_text(expr).unwrap();
3501
3502        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3503
3504        let compiler =
3505            RibCompiler::new(RibCompilerConfig::new(test_deps.component, vec![], vec![]));
3506
3507        let compilation_error = compiler.compile(expr).unwrap_err().to_string();
3508
3509        assert_eq!(
3510            compilation_error,
3511            "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'; disambiguate with a fully qualified WIT call (e.g. ns:pkg/interface.{fn}). interfaces: api1, api2\n".to_string()
3512        );
3513    }
3514
3515    #[test]
3516    async fn interpreter_durable_worker_7() {
3517        let expr = r#"
3518                let worker = instance("my-worker");
3519                let result = worker.baz("bar");
3520                result
3521            "#;
3522        let expr = Expr::from_text(expr).unwrap();
3523        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3524
3525        let compiler_config = RibCompilerConfig::new(test_deps.component, vec![], vec![]);
3526        let compiler = RibCompiler::new(compiler_config);
3527        let compiled = compiler.compile(expr).unwrap();
3528
3529        let mut rib_interpreter = test_deps.interpreter;
3530
3531        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3532
3533        assert_eq!(
3534            result.get_val().unwrap().value,
3535            Value::String("clock-baz".to_string())
3536        );
3537    }
3538
3539    #[test]
3540    async fn interpreter_durable_worker_8() {
3541        let expr = r#"
3542                let worker = instance("my-worker");
3543                let result = worker.qux("bar");
3544                result
3545            "#;
3546        let expr = Expr::from_text(expr).unwrap();
3547        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3548
3549        let compiler = RibCompiler::new(RibCompilerConfig::new(
3550            test_deps.component.clone(),
3551            vec![],
3552            vec![],
3553        ));
3554
3555        let compiled = compiler.compile(expr).unwrap_err().to_string();
3556
3557        assert_eq!(
3558            compiled,
3559            "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; use a fully qualified WIT call site to disambiguate: amazon:shopping-cart (interfaces: api1), wasi:clocks (interfaces: monotonic-clock)\n".to_string()
3560        );
3561    }
3562
3563    #[test]
3564    async fn interpreter_durable_worker_11() {
3565        let expr = r#"
3566                let worker = instance("my-worker");
3567                let invokes: list<u8> = [1, 2, 3, 4];
3568
3569                for i in invokes {
3570                    yield worker.baz("bar");
3571                };
3572
3573                "success"
3574            "#;
3575        let expr = Expr::from_text(expr).unwrap();
3576        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3577
3578        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], 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.run(compiled.byte_code).await.unwrap();
3585
3586        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3587    }
3588
3589    #[test]
3590    async fn interpreter_durable_worker_12() {
3591        let expr = r#"
3592                let worker = instance("my-worker");
3593                for i in [1, 2, 3] {
3594                   worker.foo("${i}");
3595                   yield i;
3596                }
3597            "#;
3598        let expr = Expr::from_text(expr).unwrap();
3599        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces(None);
3600
3601        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3602        let compiler = RibCompiler::new(compiler_config);
3603        let compiled = compiler.compile(expr).unwrap();
3604
3605        let mut rib_interpreter = test_deps.interpreter;
3606
3607        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3608
3609        assert_eq!(
3610            result.get_val().unwrap().value,
3611            Value::List(vec![Value::S32(1), Value::S32(2), Value::S32(3)])
3612        );
3613    }
3614
3615    #[test]
3616    async fn interpreter_durable_worker_with_resource_0() {
3617        let expr = r#"
3618                let worker = instance("my-worker");
3619                worker.cart("bar")
3620            "#;
3621        let expr = Expr::from_text(expr).unwrap();
3622        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3623
3624        let compiler = RibCompiler::new(RibCompilerConfig::new(
3625            test_deps.component.clone(),
3626            vec![],
3627            vec![],
3628        ));
3629
3630        let compiled = compiler.compile(expr);
3631
3632        assert!(compiled.is_ok());
3633    }
3634
3635    // This resource construction is a Noop, and compiler can give warnings
3636    // once we support warnings in the compiler
3637    #[test]
3638    async fn interpreter_durable_worker_with_resource_1() {
3639        let expr = r#"
3640                let worker = instance("my-worker");
3641                worker.cart("bar");
3642                "success"
3643            "#;
3644        let expr = Expr::from_text(expr).unwrap();
3645        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3646
3647        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3648        let compiler = RibCompiler::new(compiler_config);
3649        let compiled = compiler.compile(expr).unwrap();
3650
3651        let mut rib_interpreter = test_deps.interpreter;
3652
3653        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3654
3655        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3656    }
3657
3658    #[test]
3659    async fn interpreter_durable_worker_with_resource_2() {
3660        let expr = r#"
3661                let worker = instance("my-worker");
3662                let cart = worker.cart("bar");
3663                let result = cart.add-item({product-id: "mac", name: "macbook", price: 1:f32, quantity: 1:u32});
3664                result
3665            "#;
3666        let expr = Expr::from_text(expr).unwrap();
3667        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3668
3669        let compiler_config = RibCompilerConfig::new(test_deps.component, vec![], vec![]);
3670        let compiler = RibCompiler::new(compiler_config);
3671        let compiled = compiler.compile(expr).unwrap();
3672
3673        let mut rib_interpreter = test_deps.interpreter;
3674
3675        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3676
3677        assert_eq!(result, RibResult::Unit);
3678    }
3679
3680    #[test]
3681    async fn interpreter_durable_worker_with_resource_3() {
3682        let expr = r#"
3683                let worker = instance("my-worker");
3684                let cart = worker.cart("bar");
3685                cart.add-items({product-id: "mac", name: "macbook", price: 1:f32, quantity: 1:u32});
3686                "success"
3687            "#;
3688        let expr = Expr::from_text(expr).unwrap();
3689        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3690
3691        let compiler = RibCompiler::new(RibCompilerConfig::new(
3692            test_deps.component.clone(),
3693            vec![],
3694            vec![],
3695        ));
3696
3697        let compiled = compiler.compile(expr).unwrap_err().to_string();
3698
3699        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());
3700    }
3701
3702    #[test]
3703    async fn interpreter_durable_worker_with_resource_4() {
3704        let expr = r#"
3705                let worker = instance("my-worker");
3706                let cart = worker.carts("bar");
3707                cart.add-item({product-id: "mac", name: "macbook", price: 1:f32, quantity: 1:u32});
3708                "success"
3709            "#;
3710        let expr = Expr::from_text(expr).unwrap();
3711        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3712
3713        let compiler = RibCompiler::new(RibCompilerConfig::new(
3714            test_deps.component.clone(),
3715            vec![],
3716            vec![],
3717        ));
3718
3719        let compiled = compiler.compile(expr).unwrap_err().to_string();
3720
3721        assert_eq!(
3722            compiled,
3723            "error in the following rib found at line 3, column 28\n`worker.carts(\"bar\")`\ncause: invalid function call `carts`\nfunction 'carts' not found\n".to_string()
3724        );
3725    }
3726
3727    #[test]
3728    async fn interpreter_durable_worker_with_resource_5() {
3729        // Ephemeral
3730        let expr = r#"
3731                let worker = instance();
3732                let cart = worker.cart("bar");
3733                cart.add-item({product-id: "mac", name: "macbook", price: 1, quantity: 1});
3734                "success"
3735            "#;
3736        let expr = Expr::from_text(expr).unwrap();
3737        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3738
3739        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3740        let compiler = RibCompiler::new(compiler_config);
3741        let compiled = compiler.compile(expr).unwrap();
3742
3743        let mut rib_interpreter = test_deps.interpreter;
3744
3745        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3746
3747        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3748    }
3749
3750    #[test]
3751    async fn interpreter_durable_worker_with_resource_6() {
3752        // Ephemeral
3753        let expr = r#"
3754                let worker = instance();
3755                let cart = worker.cart("bar");
3756                cart.add-item({product-id: "mac", name: 1, quantity: 1, price: 1});
3757                "success"
3758            "#;
3759        let expr = Expr::from_text(expr).unwrap();
3760
3761        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3762
3763        let compiler = RibCompiler::new(RibCompilerConfig::new(
3764            test_deps.component.clone(),
3765            vec![],
3766            vec![],
3767        ));
3768
3769        let error_message = compiler.compile(expr).unwrap_err().to_string();
3770
3771        let expected = r#"
3772            error in the following rib found at line 4, column 57
3773            `1`
3774            cause: type mismatch. expected string, found s32
3775            the expression `1` is inferred as `s32` by default
3776            "#;
3777
3778        assert_eq!(error_message, strip_spaces(expected));
3779    }
3780
3781    #[test]
3782    async fn interpreter_durable_worker_with_resource_7() {
3783        let expr = r#"
3784                let worker = instance("my-worker");
3785                let cart = worker.cart("bar");
3786                cart.add-item({product-id: "mac", name: "apple", price: 1, quantity: 1});
3787                "success"
3788            "#;
3789        let expr = Expr::from_text(expr).unwrap();
3790        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3791
3792        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3793        let compiler = RibCompiler::new(compiler_config);
3794        let compiled = compiler.compile(expr).unwrap();
3795
3796        let mut rib_interpreter = test_deps.interpreter;
3797
3798        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3799
3800        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3801    }
3802
3803    #[test]
3804    async fn interpreter_durable_worker_with_resource_8() {
3805        let expr = r#"
3806                let worker = instance("my-worker");
3807                let a = "mac";
3808                let b = "apple";
3809                let c = 1;
3810                let d = 1;
3811                let cart = worker.cart("bar");
3812                cart.add-item({product-id: a, name: b, quantity: c, price: d});
3813                "success"
3814            "#;
3815        let expr = Expr::from_text(expr).unwrap();
3816        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3817        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3818        let compiler = RibCompiler::new(compiler_config);
3819        let compiled = compiler.compile(expr).unwrap();
3820
3821        let mut rib_interpreter = test_deps.interpreter;
3822
3823        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3824
3825        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
3826    }
3827
3828    #[test]
3829    async fn interpreter_durable_worker_with_resource_9() {
3830        let expr = r#"
3831                let worker = instance("my-worker");
3832                let a = "mac";
3833                let b = "apple";
3834                let c = 1;
3835                let d = 1;
3836                let cart = worker.cart("bar");
3837                cart.add-item({product-id: a, name: b, quantity: c, price: d});
3838                cart.remove-item(a);
3839                cart.update-item-quantity(a, 2);
3840                let result = cart.get-cart-contents();
3841                cart.drop();
3842                result
3843            "#;
3844        let expr = Expr::from_text(expr).unwrap();
3845        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3846        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3847        let compiler = RibCompiler::new(compiler_config);
3848        let compiled = compiler.compile(expr).unwrap();
3849
3850        let mut rib_interpreter = test_deps.interpreter;
3851
3852        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3853
3854        let expected_value = Value::List(vec![Value::Record(vec![
3855            Value::String("foo".to_string()),
3856            Value::String("bar".to_string()),
3857            Value::F32(10.0),
3858            Value::U32(2),
3859        ])]);
3860
3861        assert_eq!(result.get_val().unwrap().value, expected_value);
3862    }
3863
3864    #[test]
3865    #[ignore]
3866    async fn interpreter_durable_worker_with_resource_10() {
3867        let expr = r#"
3868                let my_worker = "my-worker";
3869                let worker = instance(my_worker);
3870                let a = "mac";
3871                let b = "apple";
3872                let c = 1;
3873                let d = 1;
3874                let cart = worker.cart("bar");
3875                cart.add-item({product-id: a, name: b, price: d, quantity: c});
3876                cart.remove-item(a);
3877                cart.update-item-quantity(a, 2);
3878                let result = cart.get-cart-contents();
3879                cart.drop();
3880                result
3881            "#;
3882        let expr = Expr::from_text(expr).unwrap();
3883        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(None);
3884
3885        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3886        let compiler = RibCompiler::new(compiler_config);
3887        let compiled = compiler.compile(expr).unwrap();
3888
3889        let mut rib_interpreter = test_deps.interpreter;
3890
3891        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3892
3893        let expected_value = Value::List(vec![Value::Record(vec![
3894            Value::String("foo".to_string()),
3895            Value::String("bar".to_string()),
3896            Value::F32(10.0),
3897            Value::U32(2),
3898        ])]);
3899
3900        assert_eq!(result.get_val().unwrap().value, expected_value);
3901    }
3902
3903    #[test]
3904    #[ignore]
3905    async fn interpreter_durable_worker_with_resource_16() {
3906        let expr = r#"
3907                let x: string = request.path.user-id;
3908                let worker = instance(x);
3909                let cart = worker.cart("bar");
3910                let result = cart.get-cart-contents();
3911                result
3912            "#;
3913
3914        let expr = Expr::from_text(expr).unwrap();
3915
3916        let mut input = HashMap::new();
3917
3918        let rib_input_key = "request";
3919
3920        let rib_input_value = ValueAndType::new(
3921            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
3922            record(vec![field("path", record(vec![field("user-id", str())]))]),
3923        );
3924
3925        input.insert(rib_input_key.to_string(), rib_input_value);
3926
3927        let rib_input = RibInput::new(input);
3928
3929        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(Some(rib_input));
3930
3931        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3932
3933        let compiler = RibCompiler::new(compiler_config);
3934
3935        let compiled = compiler.compile(expr).unwrap();
3936
3937        let mut rib_interpreter = test_deps.interpreter;
3938
3939        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3940
3941        let result_val = result.get_val().unwrap();
3942
3943        let expected_val = Value::List(vec![Value::Record(vec![
3944            Value::String("foo".to_string()),
3945            Value::String("bar".to_string()),
3946            Value::F32(10.0),
3947            Value::U32(2),
3948        ])]);
3949
3950        assert_eq!(result_val.value, expected_val)
3951    }
3952
3953    #[test]
3954    async fn interpreter_durable_worker_with_resource_17() {
3955        let expr = r#"
3956                let x: string = request.path.user-id;
3957                let min: u8 = 1;
3958                let max: u8 = 3;
3959                let result = for i in min..=max {
3960                   let worker = instance("my-worker");
3961                   let cart = worker.cart("bar");
3962                   yield cart.get-cart-contents();
3963                };
3964                result
3965            "#;
3966        let expr = Expr::from_text(expr).unwrap();
3967
3968        let mut input = HashMap::new();
3969
3970        let rib_input_key = "request";
3971
3972        let rib_input_value = ValueAndType::new(
3973            Value::Record(vec![Value::Record(vec![Value::String("user".to_string())])]),
3974            record(vec![field("path", record(vec![field("user-id", str())]))]),
3975        );
3976
3977        input.insert(rib_input_key.to_string(), rib_input_value);
3978
3979        let rib_input = RibInput::new(input);
3980
3981        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(Some(rib_input));
3982
3983        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
3984
3985        let compiler = RibCompiler::new(compiler_config);
3986
3987        let compiled = compiler.compile(expr).unwrap();
3988
3989        let mut rib_interpreter = test_deps.interpreter;
3990
3991        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
3992
3993        let result_val = result.get_val().unwrap().value;
3994
3995        let cart_contents = Value::List(vec![Value::Record(vec![
3996            Value::String("foo".to_string()),
3997            Value::String("bar".to_string()),
3998            Value::F32(10.0),
3999            Value::U32(2),
4000        ])]);
4001
4002        let expected_val = Value::List(vec![
4003            cart_contents.clone(),
4004            cart_contents.clone(),
4005            cart_contents,
4006        ]);
4007
4008        assert_eq!(result_val, expected_val);
4009    }
4010
4011    #[test]
4012    async fn interpreter_durable_worker_with_resource_18() {
4013        let expr = r#"
4014
4015            let initial = 1;
4016            let final = 5;
4017            let range = initial..final;
4018            let worker = instance("my-worker");
4019            let cart = worker.cart("bar");
4020
4021            for i in range {
4022                yield cart.add-item(request.body);
4023            };
4024
4025            "success"
4026        "#;
4027        let expr = Expr::from_text(expr).unwrap();
4028
4029        let mut input = HashMap::new();
4030
4031        let rib_input_key = "request";
4032
4033        let rib_input_value = ValueAndType::new(
4034            Value::Record(vec![Value::Record(vec![
4035                Value::String("mac-book".to_string()),
4036                Value::String("mac".to_string()),
4037                Value::U32(1),
4038                Value::F32(1.0),
4039            ])]),
4040            record(vec![field(
4041                "body",
4042                record(vec![
4043                    field("name", str()),
4044                    field("product-id", str()),
4045                    field("quantity", u32()),
4046                    field("price", f32()),
4047                ]),
4048            )]),
4049        );
4050
4051        input.insert(rib_input_key.to_string(), rib_input_value);
4052
4053        let rib_input = RibInput::new(input);
4054
4055        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(Some(rib_input));
4056
4057        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
4058
4059        let compiler = RibCompiler::new(compiler_config);
4060
4061        let compiled = compiler.compile(expr).unwrap();
4062
4063        let mut rib_interpreter = test_deps.interpreter;
4064
4065        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4066
4067        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4068    }
4069
4070    #[test]
4071    async fn interpreter_durable_worker_with_resource_19() {
4072        let expr = r#"
4073
4074            let initial = 1;
4075            let final = 5;
4076            let range = initial..final;
4077
4078            for i in range {
4079                let worker = instance("my-worker");
4080                let cart = worker.cart("bar");
4081                yield cart.add-item(request.body);
4082            };
4083
4084            "success"
4085        "#;
4086        let expr = Expr::from_text(expr).unwrap();
4087
4088        let mut input = HashMap::new();
4089
4090        let rib_input_key = "request";
4091
4092        let rib_input_value = ValueAndType::new(
4093            Value::Record(vec![Value::Record(vec![
4094                Value::String("mac-book".to_string()),
4095                Value::String("mac".to_string()),
4096                Value::U32(1),
4097                Value::F32(1.0),
4098            ])]),
4099            record(vec![field(
4100                "body",
4101                record(vec![
4102                    field("name", str()),
4103                    field("product-id", str()),
4104                    field("quantity", u32()),
4105                    field("price", f32()),
4106                ]),
4107            )]),
4108        );
4109
4110        input.insert(rib_input_key.to_string(), rib_input_value);
4111
4112        let rib_input = RibInput::new(input);
4113
4114        let test_deps = RibTestDeps::test_deps_with_indexed_resource_functions(Some(rib_input));
4115
4116        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
4117
4118        let compiler = RibCompiler::new(compiler_config);
4119
4120        let compiled = compiler.compile(expr).unwrap();
4121
4122        let mut rib_interpreter = test_deps.interpreter;
4123
4124        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4125
4126        assert_eq!(result.get_val().unwrap(), "success".into_value_and_type());
4127    }
4128
4129    #[test]
4130    async fn interpreter_custom_instance() {
4131        let expr = r#"
4132                let text = "nyc";
4133                let number = "usa";
4134                let boolean = true;
4135                let optional-str = some("optional");
4136                let optional-number = some(2);
4137                let list-of-str = ["a", "b", "c"];
4138                let tuple = (text, 1, boolean, optional-str);
4139                let record = {city: text, country: number};
4140                let result = ok(text);
4141                let result-ok = ok(text);
4142                let result-err = err(1);
4143                let variant = foo("bar");
4144                let weather-agent = weather-agent("text", 1, true, optional-str, optional-number, none, none, list-of-str, tuple, record, result, result-ok, result-err, variant);
4145                let first-result = weather-agent.get-weather("bar");
4146                let assistant-agent = assistant-agent("my assistant");
4147                let second-result = assistant-agent.ask("foo", "bar");
4148                {weather: first-result, assistant: second-result}
4149            "#;
4150
4151        let weather_agent_constructor_param_types: Vec<WitType> = vec![
4152            str(),
4153            s32(),
4154            bool(),
4155            option(str()),
4156            option(u64()),
4157            option(str()),
4158            option(u64()),
4159            list(str()),
4160            tuple(vec![str(), s32(), bool(), option(str())]),
4161            record(vec![field("city", str()), field("country", str())]),
4162            result(str(), s32()),
4163            result_ok(str()),
4164            result_err(s32()),
4165            variant(vec![
4166                case("foo", str()),
4167                case("bar", s32()),
4168                unit_case("baz"),
4169            ]),
4170        ];
4171
4172        let custom_spec1 = CustomInstanceSpec::new(
4173            "weather-agent".to_string(),
4174            weather_agent_constructor_param_types,
4175        );
4176
4177        let custom_spec2 = CustomInstanceSpec::new("assistant-agent".to_string(), vec![str()]);
4178
4179        let expr = Expr::from_text(expr).unwrap();
4180        let test_deps = RibTestDeps::test_deps_with_multiple_interfaces_simple(None);
4181
4182        let compiler_config = RibCompilerConfig::new(
4183            test_deps.component.clone(),
4184            vec![],
4185            vec![custom_spec1, custom_spec2],
4186        );
4187        let compiler = RibCompiler::new(compiler_config);
4188        let compiled = compiler
4189            .compile(expr)
4190            .map_err(|err| err.to_string())
4191            .unwrap();
4192
4193        let mut rib_interpreter = test_deps.interpreter;
4194
4195        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4196
4197        let expected = Value::Record(vec![
4198            Value::Record(vec![
4199                // worker-name
4200                Value::String(
4201                    "weather-agent(\"text\",1,true,some(\"optional\"),some(2),none,none,[\"a\", \"b\", \"c\"],(\"nyc\", 1, true, some(\"optional\")),{city: \"nyc\", country: \"usa\"},ok(\"nyc\"),ok(\"nyc\"),err(1),foo(\"bar\"))".to_string(),
4202                ),
4203                // function-name
4204                Value::String("my:agent/weather-agent.{get-weather}".to_string()),
4205                // args concatenated
4206                Value::String("\"bar\"".to_string()),
4207            ]),
4208            Value::Record(vec![
4209                // worker-name
4210                Value::String("assistant-agent(\"my assistant\")".to_string()),
4211                // function-name
4212                Value::String("my:agent/assistant-agent.{ask}".to_string()),
4213                // args concatenated
4214                Value::String("\"foo\"\"bar\"".to_string()),
4215            ]),
4216        ]);
4217
4218        assert_eq!(result.get_val().unwrap().value, expected);
4219    }
4220
4221    #[test]
4222    async fn interpreter_custom_instance_conflicting_variants() {
4223        let expr = r#"
4224                let x = instance("abc");
4225                let r1 = x.func1(foo("bar"));
4226                let r2 = x.func2(foo(["baz", "qux"]));
4227                {result1: r1, result2: r2}
4228            "#;
4229
4230        let expr = Expr::from_text(expr).unwrap();
4231        let test_deps = RibTestDeps::test_deps_with_variant_conflicts(None);
4232
4233        let compiler_config = RibCompilerConfig::new(test_deps.component.clone(), vec![], vec![]);
4234        let compiler = RibCompiler::new(compiler_config);
4235        let compiled = compiler
4236            .compile(expr)
4237            .map_err(|err| err.to_string())
4238            .unwrap();
4239
4240        let mut rib_interpreter = test_deps.interpreter;
4241
4242        let result = rib_interpreter.run(compiled.byte_code).await.unwrap();
4243
4244        let expected = Value::Record(vec![
4245            Value::Variant {
4246                case_idx: 0,
4247                case_value: Some(Box::new(Value::String("bar".to_string()))),
4248            },
4249            Value::Variant {
4250                case_idx: 0,
4251                case_value: Some(Box::new(Value::List(vec![
4252                    Value::String("baz".to_string()),
4253                    Value::String("qux".to_string()),
4254                ]))),
4255            },
4256        ]);
4257        assert_eq!(result.get_val().unwrap().value, expected);
4258    }
4259
4260    mod test_utils {
4261        use crate::interpreter::rib_interpreter::internal::NoopRibFunctionInvoke;
4262        use crate::interpreter::rib_interpreter::Interpreter;
4263        use crate::wit_type::{
4264            case, f32, field, handle, list, option, r#enum, record, result, s32, str, tuple, u32,
4265            u64, unit_case, variant,
4266        };
4267        use crate::wit_type::{
4268            AnalysedResourceId, AnalysedResourceMode, TypeHandle, WitExport, WitFunction,
4269            WitFunctionParameter, WitFunctionResult, WitInterface, WitType,
4270        };
4271        use crate::{print_value_and_type, IntoValueAndType, Value, ValueAndType};
4272        use crate::{
4273            ComponentDependency, ComponentDependencyKey, DefaultWorkerNameGenerator,
4274            EvaluatedFnArgs, EvaluatedFqFn, EvaluatedWorkerName, GenerateWorkerName,
4275            GetLiteralValue, InstructionId, RibComponentFunctionInvoke, RibFunctionInvokeResult,
4276            RibInput,
4277        };
4278        use async_trait::async_trait;
4279        use std::sync::Arc;
4280        use uuid::Uuid;
4281
4282        pub(crate) fn strip_spaces(input: &str) -> String {
4283            let lines = input.lines();
4284
4285            let first_line = lines
4286                .clone()
4287                .find(|line| !line.trim().is_empty())
4288                .unwrap_or("");
4289            let margin_width = first_line.chars().take_while(|c| c.is_whitespace()).count();
4290
4291            let result = lines
4292                .map(|line| {
4293                    if line.trim().is_empty() {
4294                        String::new()
4295                    } else {
4296                        line[margin_width..].to_string()
4297                    }
4298                })
4299                .collect::<Vec<String>>()
4300                .join("\n");
4301
4302            result.strip_prefix("\n").unwrap_or(&result).to_string()
4303        }
4304
4305        pub(crate) fn get_analysed_type_variant() -> WitType {
4306            variant(vec![
4307                case("register-user", u64()),
4308                case("process-user", str()),
4309                unit_case("validate"),
4310            ])
4311        }
4312
4313        pub(crate) fn get_analysed_type_record() -> WitType {
4314            record(vec![
4315                field(
4316                    "request",
4317                    record(vec![field("path", record(vec![field("user", str())]))]),
4318                ),
4319                field("y", str()),
4320            ])
4321        }
4322
4323        pub(crate) fn get_analysed_type_result() -> WitType {
4324            result(u64(), str())
4325        }
4326
4327        pub(crate) fn get_analysed_type_enum() -> WitType {
4328            r#enum(&["prod", "dev", "test"])
4329        }
4330
4331        pub(crate) fn get_analysed_typ_str() -> WitType {
4332            str()
4333        }
4334
4335        pub(crate) fn get_analysed_typ_u64() -> WitType {
4336            u64()
4337        }
4338
4339        pub(crate) fn get_analysed_type_tuple() -> WitType {
4340            tuple(vec![
4341                get_analysed_typ_u64(),
4342                get_analysed_type_result(),
4343                get_analysed_typ_str(),
4344                get_analysed_type_record(),
4345                get_analysed_type_variant(),
4346                get_analysed_type_variant(),
4347                get_analysed_type_variant(),
4348                get_analysed_type_enum(),
4349                get_analysed_type_enum(),
4350                get_analysed_type_enum(),
4351            ])
4352        }
4353
4354        pub(crate) fn configurable_metadata(
4355            function_name: &str,
4356            input_types: Vec<WitType>,
4357            output: Option<WitType>,
4358        ) -> ComponentDependency {
4359            let analysed_function_parameters = input_types
4360                .into_iter()
4361                .enumerate()
4362                .map(|(index, typ)| WitFunctionParameter {
4363                    name: format!("param{index}"),
4364                    typ,
4365                })
4366                .collect();
4367
4368            let result = output.map(|typ| WitFunctionResult { typ });
4369
4370            let component_info = ComponentDependencyKey {
4371                component_name: "foo".to_string(),
4372                component_id: Uuid::new_v4(),
4373                component_revision: 0,
4374                root_package_name: None,
4375                root_package_version: None,
4376            };
4377
4378            let exports = vec![WitExport::Function(WitFunction {
4379                name: function_name.to_string(),
4380                parameters: analysed_function_parameters,
4381                result,
4382            })];
4383            ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
4384        }
4385
4386        pub(crate) fn get_metadata_with_resource_with_params() -> ComponentDependency {
4387            get_metadata_with_resource(vec![WitFunctionParameter {
4388                name: "user-id".to_string(),
4389                typ: str(),
4390            }])
4391        }
4392
4393        pub(crate) fn get_metadata_with_resource_without_params() -> ComponentDependency {
4394            get_metadata_with_resource(vec![])
4395        }
4396
4397        pub(crate) fn get_metadata_simple_with_variant_conflicts() -> ComponentDependency {
4398            let func1 = WitFunction {
4399                name: "func1".to_string(),
4400                parameters: vec![WitFunctionParameter {
4401                    name: "arg1".to_string(),
4402                    typ: variant(vec![case("foo", str())]),
4403                }],
4404                result: Some(WitFunctionResult { typ: str() }),
4405            };
4406
4407            let func2 = WitFunction {
4408                name: "func2".to_string(),
4409                parameters: vec![WitFunctionParameter {
4410                    name: "arg1".to_string(),
4411                    typ: variant(vec![
4412                        case("foo", list(str())), // just different types to that of the foo and bar
4413                    ]),
4414                }],
4415                result: Some(WitFunctionResult { typ: str() }),
4416            };
4417
4418            let component_info = ComponentDependencyKey {
4419                component_name: "foo".to_string(),
4420                component_id: Uuid::new_v4(),
4421                component_revision: 0,
4422                root_package_name: None,
4423                root_package_version: None,
4424            };
4425
4426            let exports = vec![WitExport::Function(func1), WitExport::Function(func2)];
4427            ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
4428        }
4429
4430        pub(crate) fn get_metadata_with_multiple_interfaces_simple() -> ComponentDependency {
4431            // Exist in only amazon:shopping-cart/api1
4432            let get_weather = WitFunction {
4433                name: "get-weather".to_string(),
4434                parameters: vec![WitFunctionParameter {
4435                    name: "arg1".to_string(),
4436                    typ: str(),
4437                }],
4438                result: Some(WitFunctionResult { typ: str() }),
4439            };
4440
4441            let ask = WitFunction {
4442                name: "ask".to_string(),
4443                parameters: vec![
4444                    WitFunctionParameter {
4445                        name: "arg1".to_string(),
4446                        typ: str(),
4447                    },
4448                    WitFunctionParameter {
4449                        name: "arg2".to_string(),
4450                        typ: str(),
4451                    },
4452                ],
4453                result: Some(WitFunctionResult { typ: s32() }),
4454            };
4455
4456            let analysed_export1 = WitExport::Interface(WitInterface {
4457                name: "my:agent/weather-agent".to_string(),
4458                functions: vec![get_weather],
4459            });
4460
4461            let analysed_export2 = WitExport::Interface(WitInterface {
4462                name: "my:agent/assistant-agent".to_string(),
4463                functions: vec![ask],
4464            });
4465
4466            let analysed_export3 = WitExport::Function(WitFunction {
4467                name: "variant-param".to_string(),
4468                parameters: vec![WitFunctionParameter {
4469                    name: "arg1".to_string(),
4470                    typ: variant(vec![case("foo", str()), case("bar", s32())]),
4471                }],
4472                result: Some(WitFunctionResult { typ: str() }),
4473            });
4474
4475            let component_info = ComponentDependencyKey {
4476                component_name: "foo".to_string(),
4477                component_id: Uuid::new_v4(),
4478                component_revision: 0,
4479                root_package_name: None,
4480                root_package_version: None,
4481            };
4482
4483            let exports = vec![analysed_export1, analysed_export2, analysed_export3];
4484            ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
4485        }
4486
4487        pub(crate) fn get_metadata_with_multiple_interfaces() -> ComponentDependency {
4488            // Exist in only amazon:shopping-cart/api1
4489            let analysed_function_in_api1 = WitFunction {
4490                name: "foo".to_string(),
4491                parameters: vec![WitFunctionParameter {
4492                    name: "arg1".to_string(),
4493                    typ: str(),
4494                }],
4495                result: Some(WitFunctionResult { typ: str() }),
4496            };
4497
4498            let analysed_function_in_api1_number = WitFunction {
4499                name: "foo-number".to_string(),
4500                parameters: vec![
4501                    WitFunctionParameter {
4502                        name: "arg1".to_string(),
4503                        typ: u64(),
4504                    },
4505                    WitFunctionParameter {
4506                        name: "arg2".to_string(),
4507                        typ: s32(),
4508                    },
4509                ],
4510                result: Some(WitFunctionResult { typ: s32() }),
4511            };
4512
4513            // Exist in both amazon:shopping-cart/api1 and amazon:shopping-cart/api2
4514            let analysed_function_in_api1_and_api2 = WitFunction {
4515                name: "bar".to_string(),
4516                parameters: vec![WitFunctionParameter {
4517                    name: "arg1".to_string(),
4518                    typ: str(),
4519                }],
4520                result: Some(WitFunctionResult { typ: str() }),
4521            };
4522
4523            // Exist in only wasi:clocks/monotonic-clock
4524            let analysed_function_in_wasi = WitFunction {
4525                name: "baz".to_string(),
4526                parameters: vec![WitFunctionParameter {
4527                    name: "arg1".to_string(),
4528                    typ: str(),
4529                }],
4530                result: Some(WitFunctionResult { typ: str() }),
4531            };
4532
4533            // Exist in wasi:clocks/monotonic-clock and amazon:shopping-cart/api1
4534            let analysed_function_in_wasi_and_api1 = WitFunction {
4535                name: "qux".to_string(),
4536                parameters: vec![WitFunctionParameter {
4537                    name: "arg1".to_string(),
4538                    typ: str(),
4539                }],
4540                result: Some(WitFunctionResult { typ: str() }),
4541            };
4542
4543            let analysed_export1 = WitExport::Interface(WitInterface {
4544                name: "amazon:shopping-cart/api1".to_string(),
4545                functions: vec![
4546                    analysed_function_in_api1,
4547                    analysed_function_in_api1_number,
4548                    analysed_function_in_api1_and_api2.clone(),
4549                    analysed_function_in_wasi_and_api1.clone(),
4550                ],
4551            });
4552
4553            let analysed_export2 = WitExport::Interface(WitInterface {
4554                name: "amazon:shopping-cart/api2".to_string(),
4555                functions: vec![analysed_function_in_api1_and_api2],
4556            });
4557
4558            let analysed_export3 = WitExport::Interface(WitInterface {
4559                name: "wasi:clocks/monotonic-clock".to_string(),
4560                functions: vec![
4561                    analysed_function_in_wasi,
4562                    analysed_function_in_wasi_and_api1,
4563                ],
4564            });
4565
4566            let component_info = ComponentDependencyKey {
4567                component_name: "foo".to_string(),
4568                component_id: Uuid::new_v4(),
4569                component_revision: 0,
4570                root_package_name: None,
4571                root_package_version: None,
4572            };
4573
4574            let exports = vec![analysed_export1, analysed_export2, analysed_export3];
4575            ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
4576        }
4577
4578        fn get_metadata_with_resource(
4579            resource_constructor_params: Vec<WitFunctionParameter>,
4580        ) -> ComponentDependency {
4581            let instance = WitExport::Interface(WitInterface {
4582                name: "golem:it/api".to_string(),
4583                functions: vec![
4584                    WitFunction {
4585                        name: "[constructor]cart".to_string(),
4586                        parameters: resource_constructor_params,
4587                        result: Some(WitFunctionResult {
4588                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4589                        }),
4590                    },
4591                    WitFunction {
4592                        name: "[static]cart.create".to_string(),
4593                        parameters: vec![WitFunctionParameter {
4594                            name: "item-name".to_string(),
4595                            typ: str(),
4596                        }],
4597                        result: Some(WitFunctionResult {
4598                            typ: WitType::Handle(TypeHandle {
4599                                name: Some("cart".to_string()),
4600                                owner: Some("golem:it/api".to_string()),
4601                                resource_id: AnalysedResourceId(0),
4602                                mode: AnalysedResourceMode::Owned,
4603                            }),
4604                        }),
4605                    },
4606                    WitFunction {
4607                        name: "[static]cart.create-safe".to_string(),
4608                        parameters: vec![WitFunctionParameter {
4609                            name: "item-name".to_string(),
4610                            typ: str(),
4611                        }],
4612                        result: Some(WitFunctionResult {
4613                            typ: result(
4614                                WitType::Handle(TypeHandle {
4615                                    name: Some("cart".to_string()),
4616                                    owner: Some("golem:it/api".to_string()),
4617                                    resource_id: AnalysedResourceId(0),
4618                                    mode: AnalysedResourceMode::Owned,
4619                                }),
4620                                str(),
4621                            ),
4622                        }),
4623                    },
4624                    WitFunction {
4625                        name: "[method]cart.add-item".to_string(),
4626                        parameters: vec![
4627                            WitFunctionParameter {
4628                                name: "self".to_string(),
4629                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4630                            },
4631                            WitFunctionParameter {
4632                                name: "item".to_string(),
4633                                typ: record(vec![
4634                                    field("product-id", str()),
4635                                    field("name", str()),
4636                                    field("price", f32()),
4637                                    field("quantity", u32()),
4638                                ]),
4639                            },
4640                        ],
4641                        result: None,
4642                    },
4643                    WitFunction {
4644                        name: "[method]cart.remove-item".to_string(),
4645                        parameters: vec![
4646                            WitFunctionParameter {
4647                                name: "self".to_string(),
4648                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4649                            },
4650                            WitFunctionParameter {
4651                                name: "product-id".to_string(),
4652                                typ: str(),
4653                            },
4654                        ],
4655                        result: None,
4656                    },
4657                    WitFunction {
4658                        name: "[method]cart.update-item-quantity".to_string(),
4659                        parameters: vec![
4660                            WitFunctionParameter {
4661                                name: "self".to_string(),
4662                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4663                            },
4664                            WitFunctionParameter {
4665                                name: "product-id".to_string(),
4666                                typ: str(),
4667                            },
4668                            WitFunctionParameter {
4669                                name: "quantity".to_string(),
4670                                typ: u32(),
4671                            },
4672                        ],
4673                        result: None,
4674                    },
4675                    WitFunction {
4676                        name: "[method]cart.checkout".to_string(),
4677                        parameters: vec![WitFunctionParameter {
4678                            name: "self".to_string(),
4679                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4680                        }],
4681                        result: Some(WitFunctionResult {
4682                            typ: variant(vec![
4683                                case("error", str()),
4684                                case("success", record(vec![field("order-id", str())])),
4685                            ]),
4686                        }),
4687                    },
4688                    WitFunction {
4689                        name: "[method]cart.get-cart-contents".to_string(),
4690                        parameters: vec![WitFunctionParameter {
4691                            name: "self".to_string(),
4692                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4693                        }],
4694                        result: Some(WitFunctionResult {
4695                            typ: list(record(vec![
4696                                field("product-id", str()),
4697                                field("name", str()),
4698                                field("price", f32()),
4699                                field("quantity", u32()),
4700                            ])),
4701                        }),
4702                    },
4703                    WitFunction {
4704                        name: "[method]cart.merge-with".to_string(),
4705                        parameters: vec![
4706                            WitFunctionParameter {
4707                                name: "self".to_string(),
4708                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4709                            },
4710                            WitFunctionParameter {
4711                                name: "other-cart".to_string(),
4712                                typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Borrowed),
4713                            },
4714                        ],
4715                        result: None,
4716                    },
4717                    WitFunction {
4718                        name: "[drop]cart".to_string(),
4719                        parameters: vec![WitFunctionParameter {
4720                            name: "self".to_string(),
4721                            typ: handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4722                        }],
4723                        result: None,
4724                    },
4725                ],
4726            });
4727
4728            let component_info = ComponentDependencyKey {
4729                component_name: "foo".to_string(),
4730                component_id: Uuid::new_v4(),
4731                component_revision: 0,
4732                root_package_name: None,
4733                root_package_version: None,
4734            };
4735
4736            ComponentDependency::from_wit_metadata(component_info, &[instance]).unwrap()
4737        }
4738
4739        pub(crate) fn get_value_and_type(
4740            analysed_type: &WitType,
4741            wasm_wave_str: &str,
4742        ) -> ValueAndType {
4743            crate::parse_value_and_type(analysed_type, wasm_wave_str).unwrap()
4744        }
4745
4746        pub(crate) fn interpreter_with_noop_function_invoke(
4747            input: Option<RibInput>,
4748        ) -> Interpreter {
4749            let invoke: Arc<dyn RibComponentFunctionInvoke + Send + Sync> =
4750                Arc::new(NoopRibFunctionInvoke);
4751
4752            Interpreter {
4753                input: input.unwrap_or_default(),
4754                invoke,
4755                generate_worker_name: Arc::new(DefaultWorkerNameGenerator),
4756            }
4757        }
4758
4759        // Interpreter which always returns a specific response
4760        pub(crate) fn interpreter_with_static_function_response(
4761            result_value: &ValueAndType,
4762            input: Option<RibInput>,
4763        ) -> Interpreter {
4764            let value = result_value.clone();
4765
4766            let invoke = Arc::new(TestInvoke1 { value });
4767
4768            Interpreter {
4769                input: input.unwrap_or_default(),
4770                invoke,
4771                generate_worker_name: Arc::new(DefaultWorkerNameGenerator),
4772            }
4773        }
4774
4775        // The interpreter that always returns a record value consisting of function name, worker name etc
4776        // for every function calls in Rib, so tests can assert the invoke target (worker name, function, args).
4777        pub(crate) fn interpreter_with_resource_function_invoke_impl(
4778            rib_input: Option<RibInput>,
4779        ) -> Interpreter {
4780            let invoke: Arc<dyn RibComponentFunctionInvoke + Send + Sync> =
4781                Arc::new(ResourceFunctionsInvoke);
4782
4783            Interpreter {
4784                input: rib_input.unwrap_or_default(),
4785                invoke,
4786                generate_worker_name: Arc::new(DefaultWorkerNameGenerator),
4787            }
4788        }
4789
4790        // A simple interpreter that returns response based on the function
4791        pub(crate) fn interpreter_for_global_functions(input: Option<RibInput>) -> Interpreter {
4792            let invoke = Arc::new(TestInvoke3);
4793
4794            Interpreter {
4795                input: input.unwrap_or_default(),
4796                invoke,
4797                generate_worker_name: Arc::new(DefaultWorkerNameGenerator),
4798            }
4799        }
4800
4801        struct TestInvoke1 {
4802            value: ValueAndType,
4803        }
4804
4805        #[async_trait]
4806        impl RibComponentFunctionInvoke for TestInvoke1 {
4807            async fn invoke(
4808                &self,
4809                _component_dependency_key: ComponentDependencyKey,
4810                _instruction_id: &InstructionId,
4811                _worker_name: EvaluatedWorkerName,
4812                _fqn: EvaluatedFqFn,
4813                _args: EvaluatedFnArgs,
4814                _return_type: Option<WitType>,
4815            ) -> RibFunctionInvokeResult {
4816                let value = self.value.clone();
4817                Ok(Some(value))
4818            }
4819        }
4820
4821        struct PassThroughFunctionInvoke;
4822
4823        #[async_trait]
4824        impl RibComponentFunctionInvoke for PassThroughFunctionInvoke {
4825            async fn invoke(
4826                &self,
4827                _component_dependency_key: ComponentDependencyKey,
4828                _instruction_id: &InstructionId,
4829                worker_name: EvaluatedWorkerName,
4830                function_name: EvaluatedFqFn,
4831                args: EvaluatedFnArgs,
4832                _return_type: Option<WitType>,
4833            ) -> RibFunctionInvokeResult {
4834                let analysed_type = record(vec![
4835                    field("worker-name", str()),
4836                    field("function-name", str()),
4837                    field("args0", u64()),
4838                    field("args1", u32()),
4839                ]);
4840
4841                let worker_name = Value::String(worker_name.0);
4842                let function_name = Value::String(function_name.0);
4843                let args0 = args.0[0].value.clone();
4844                let args1 = args.0[1].value.clone();
4845
4846                let value = Value::Record(vec![worker_name, function_name, args0, args1]);
4847
4848                Ok(Some(ValueAndType::new(value, analysed_type)))
4849            }
4850        }
4851
4852        struct ResourceFunctionsInvoke;
4853
4854        #[async_trait]
4855        impl RibComponentFunctionInvoke for ResourceFunctionsInvoke {
4856            async fn invoke(
4857                &self,
4858                _component_dependency_key: ComponentDependencyKey,
4859                _instruction_id: &InstructionId,
4860                worker_name: EvaluatedWorkerName,
4861                function_name: EvaluatedFqFn,
4862                args: EvaluatedFnArgs,
4863                _return_type: Option<WitType>,
4864            ) -> RibFunctionInvokeResult {
4865                match function_name.0.as_str() {
4866                    "golem:it/api.{cart.new}" => {
4867                        let worker_name = worker_name.0;
4868
4869                        let uri = format!(
4870                            "urn:worker:99738bab-a3bf-4a12-8830-b6fd783d1ef2/{worker_name}"
4871                        );
4872                        Ok(ValueAndType::new(
4873                            Value::Handle {
4874                                uri,
4875                                resource_id: 0,
4876                            },
4877                            handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4878                        )
4879                        .into())
4880                    }
4881
4882                    "golem:it/api.{cart.checkout}" => {
4883                        let result_type = variant(vec![
4884                            case("error", str()),
4885                            case("success", record(vec![field("order-id", str())])),
4886                        ]);
4887
4888                        let result_value = get_value_and_type(
4889                            &result_type,
4890                            r#"
4891                            success({order-id: "foo"})
4892                            "#,
4893                        );
4894
4895                        Ok(Some(result_value))
4896                    }
4897
4898                    "golem:it/api.{cart.add-item}" => Ok(None),
4899
4900                    "golem:it/api.{cart.update-item-quantity}" => Ok(None),
4901
4902                    "golem:it/api.{cart.remove-item}" => Ok(None),
4903
4904                    "golem:it/api.{cart.drop}" => Ok(None),
4905
4906                    "golem:it/api.{cart.get-cart-contents}" => {
4907                        let typ = list(record(vec![
4908                            field("product-id", str()),
4909                            field("name", str()),
4910                            field("price", f32()),
4911                            field("quantity", u32()),
4912                        ]));
4913
4914                        let value = Value::Record(vec![
4915                            Value::String("foo".to_string()),
4916                            Value::String("bar".to_string()),
4917                            Value::F32(10.0),
4918                            Value::U32(2),
4919                        ]);
4920
4921                        Ok(Some(ValueAndType::new(Value::List(vec![value]), typ)))
4922                    }
4923
4924                    "golem:it/api.{[static]cart.create}" => {
4925                        let uri = format!(
4926                            "urn:worker:99738bab-a3bf-4a12-8830-b6fd783d1ef2/{}",
4927                            worker_name.0
4928                        );
4929
4930                        let value = Value::Handle {
4931                            uri,
4932                            resource_id: 0,
4933                        };
4934
4935                        Ok(Some(ValueAndType::new(
4936                            value,
4937                            handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4938                        )))
4939                    }
4940
4941                    "golem:it/api.{[static]cart.create-safe}" => {
4942                        let uri = format!(
4943                            "urn:worker:99738bab-a3bf-4a12-8830-b6fd783d1ef2/{}",
4944                            worker_name.0
4945                        );
4946
4947                        let resource = Value::Handle {
4948                            uri,
4949                            resource_id: 0,
4950                        };
4951
4952                        let value = Value::Result(Ok(Some(Box::new(resource))));
4953
4954                        Ok(Some(ValueAndType::new(
4955                            value,
4956                            result(
4957                                handle(AnalysedResourceId(0), AnalysedResourceMode::Owned),
4958                                str(),
4959                            ),
4960                        )))
4961                    }
4962
4963                    "golem:it/api.{cart.pass-through}" => {
4964                        let worker_name = worker_name.0;
4965                        let function_args = args.0[1..].to_vec();
4966
4967                        let mut arg_types = vec![];
4968
4969                        for (index, value_and_type) in function_args.iter().enumerate() {
4970                            let name = format!("args{index}");
4971                            let value = value_and_type.typ.clone();
4972                            arg_types.push(field(name.as_str(), value));
4973                        }
4974
4975                        let function_name = function_name.0.into_value_and_type();
4976
4977                        let mut analysed_type_pairs = vec![];
4978                        analysed_type_pairs.push(field("worker-name", str()));
4979                        analysed_type_pairs.push(field("function-name", str()));
4980                        analysed_type_pairs.extend(arg_types);
4981
4982                        let mut values = vec![];
4983
4984                        values.push(Value::String(worker_name));
4985                        values.push(function_name.value);
4986
4987                        for arg_value in function_args {
4988                            values.push(arg_value.value);
4989                        }
4990
4991                        let value_and_type =
4992                            ValueAndType::new(Value::Record(values), record(analysed_type_pairs));
4993
4994                        Ok(Some(value_and_type))
4995                    }
4996
4997                    _ => Err(format!("unexpected function name: {}", function_name.0).into()),
4998                }
4999            }
5000        }
5001
5002        struct SimpleVariantConflictInvoke;
5003
5004        #[async_trait]
5005        impl RibComponentFunctionInvoke for SimpleVariantConflictInvoke {
5006            async fn invoke(
5007                &self,
5008                _component_dependency_key: ComponentDependencyKey,
5009                _instruction_id: &InstructionId,
5010                _worker_name: EvaluatedWorkerName,
5011                function_name: EvaluatedFqFn,
5012                args: EvaluatedFnArgs,
5013                _return_type: Option<WitType>,
5014            ) -> RibFunctionInvokeResult {
5015                let arg = args.0.first().unwrap();
5016
5017                match function_name.0.as_str() {
5018                    "func1" | "func2" => Ok(Some(arg.clone())),
5019                    _ => Err(format!("unexpected function name: {}", function_name.0).into()),
5020                }
5021            }
5022        }
5023
5024        struct CustomInstanceFunctionInvoke;
5025        #[async_trait]
5026        impl RibComponentFunctionInvoke for CustomInstanceFunctionInvoke {
5027            async fn invoke(
5028                &self,
5029                _component_dependency_key: ComponentDependencyKey,
5030                _instruction_id: &InstructionId,
5031                worker_name: EvaluatedWorkerName,
5032                function_name: EvaluatedFqFn,
5033                args: EvaluatedFnArgs,
5034                _return_type: Option<WitType>,
5035            ) -> RibFunctionInvokeResult {
5036                let mut arguments_concatenated = String::new();
5037
5038                for arg in args.0 {
5039                    let arg_str = print_value_and_type(&arg)?;
5040                    arguments_concatenated.push_str(arg_str.as_str());
5041                }
5042
5043                let result_value = ValueAndType::new(
5044                    Value::Record(vec![
5045                        Value::String(worker_name.0),
5046                        Value::String(function_name.0.clone()),
5047                        Value::String(arguments_concatenated),
5048                    ]),
5049                    record(vec![
5050                        field("worker-name", str()),
5051                        field("function-name", str()),
5052                        field("args", str()),
5053                    ]),
5054                );
5055
5056                match function_name.0.as_str() {
5057                    "my:agent/weather-agent.{get-weather}" => Ok(Some(result_value)),
5058
5059                    "my:agent/assistant-agent.{ask}" => Ok(Some(result_value)),
5060
5061                    _ => Err(format!("unexpected function name: {}", function_name.0).into()),
5062                }
5063            }
5064        }
5065
5066        struct MultiplePackageFunctionInvoke;
5067
5068        #[async_trait]
5069        impl RibComponentFunctionInvoke for MultiplePackageFunctionInvoke {
5070            async fn invoke(
5071                &self,
5072                _component_dependency_key: ComponentDependencyKey,
5073                _instruction_id: &InstructionId,
5074                _worker_name: EvaluatedWorkerName,
5075                function_name: EvaluatedFqFn,
5076                _args: EvaluatedFnArgs,
5077                _return_type: Option<WitType>,
5078            ) -> RibFunctionInvokeResult {
5079                match function_name.0.as_str() {
5080                    "amazon:shopping-cart/api1.{foo}" => {
5081                        let result_value =
5082                            ValueAndType::new(Value::String("foo".to_string()), str());
5083
5084                        Ok(Some(result_value))
5085                    }
5086
5087                    "amazon:shopping-cart/api1.{foo-number}" => {
5088                        let result_value = ValueAndType::new(Value::S32(1), s32());
5089
5090                        Ok(Some(result_value))
5091                    }
5092
5093                    "amazon:shopping-cart/api1.{bar}" => {
5094                        let result_value =
5095                            ValueAndType::new(Value::String("api1-bar".to_string()), str());
5096
5097                        Ok(Some(result_value))
5098                    }
5099
5100                    "amazon:shopping-cart/api1.{qux}" => {
5101                        let result_value =
5102                            ValueAndType::new(Value::String("qux".to_string()), str());
5103
5104                        Ok(Some(result_value))
5105                    }
5106
5107                    "amazon:shopping-cart/api2.{bar}" => {
5108                        let result_value =
5109                            ValueAndType::new(Value::String("api2-bar".to_string()), str());
5110
5111                        Ok(Some(result_value))
5112                    }
5113
5114                    "wasi:clocks/monotonic-clock.{baz}" => {
5115                        let result_value =
5116                            ValueAndType::new(Value::String("clock-baz".to_string()), str());
5117
5118                        Ok(Some(result_value))
5119                    }
5120
5121                    "wasi:clocks/monotonic-clock.{qux}" => {
5122                        let result_value =
5123                            ValueAndType::new(Value::String("clock-qux".to_string()), str());
5124
5125                        Ok(Some(result_value))
5126                    }
5127
5128                    _ => Err(format!("unexpected function name: {}", function_name.0).into()),
5129                }
5130            }
5131        }
5132
5133        pub(crate) struct StaticWorkerNameGenerator;
5134
5135        impl GenerateWorkerName for StaticWorkerNameGenerator {
5136            fn generate_worker_name(&self) -> String {
5137                "test-worker".to_string()
5138            }
5139        }
5140
5141        pub(crate) struct RibTestDeps {
5142            pub(crate) component: ComponentDependency,
5143            pub(crate) interpreter: Interpreter,
5144        }
5145
5146        impl RibTestDeps {
5147            pub(crate) fn test_deps_with_global_functions() -> RibTestDeps {
5148                let component = get_component_dependency_with_global_functions();
5149                let interpreter = interpreter_for_global_functions(None);
5150
5151                RibTestDeps {
5152                    component,
5153                    interpreter,
5154                }
5155            }
5156
5157            pub(crate) fn test_deps_with_resource_functions(
5158                rib_input: Option<RibInput>,
5159            ) -> RibTestDeps {
5160                let component = get_metadata_with_resource_without_params();
5161                let interpreter = interpreter_with_resource_function_invoke_impl(rib_input);
5162
5163                RibTestDeps {
5164                    component,
5165                    interpreter,
5166                }
5167            }
5168
5169            pub(crate) fn test_deps_with_indexed_resource_functions(
5170                rib_input: Option<RibInput>,
5171            ) -> RibTestDeps {
5172                let component = get_metadata_with_resource_with_params();
5173                let interpreter = interpreter_with_resource_function_invoke_impl(rib_input);
5174
5175                RibTestDeps {
5176                    component,
5177                    interpreter,
5178                }
5179            }
5180
5181            // A pass through function simply pass through the information embedded in a function call
5182            // such as function name, the worker name and the arguments used to invoke the call
5183            // allowing us to cross verify if the invoke is correct
5184            pub(crate) fn test_deps_for_pass_through_function() -> RibTestDeps {
5185                let exports = vec![WitExport::Function(WitFunction {
5186                    name: "pass-through".to_string(),
5187                    parameters: vec![
5188                        WitFunctionParameter {
5189                            name: "item".to_string(),
5190                            typ: u64(),
5191                        },
5192                        WitFunctionParameter {
5193                            name: "item".to_string(),
5194                            typ: u32(),
5195                        },
5196                    ],
5197                    result: Some(WitFunctionResult {
5198                        typ: record(vec![
5199                            field("worker-name", option(str())),
5200                            field("function-name", str()),
5201                            field("args0", u64()),
5202                            field("args1", u32()),
5203                        ]),
5204                    }),
5205                })];
5206
5207                let component_info = ComponentDependencyKey {
5208                    component_name: "foo".to_string(),
5209                    component_id: Uuid::new_v4(),
5210                    component_revision: 0,
5211                    root_package_name: None,
5212                    root_package_version: None,
5213                };
5214
5215                let component =
5216                    ComponentDependency::from_wit_metadata(component_info, &exports).unwrap();
5217
5218                let interpreter = Interpreter::new(
5219                    RibInput::default(),
5220                    Arc::new(PassThroughFunctionInvoke),
5221                    Arc::new(StaticWorkerNameGenerator),
5222                );
5223
5224                RibTestDeps {
5225                    component,
5226                    interpreter,
5227                }
5228            }
5229
5230            pub(crate) fn test_deps_with_multiple_interfaces_simple(
5231                rib_input: Option<RibInput>,
5232            ) -> RibTestDeps {
5233                let component = get_metadata_with_multiple_interfaces_simple();
5234                let interpreter = Interpreter::new(
5235                    rib_input.unwrap_or_default(),
5236                    Arc::new(CustomInstanceFunctionInvoke),
5237                    Arc::new(StaticWorkerNameGenerator),
5238                );
5239
5240                RibTestDeps {
5241                    component,
5242                    interpreter,
5243                }
5244            }
5245
5246            pub(crate) fn test_deps_with_variant_conflicts(
5247                rib_input: Option<RibInput>,
5248            ) -> RibTestDeps {
5249                let component = get_metadata_simple_with_variant_conflicts();
5250                let interpreter = Interpreter::new(
5251                    rib_input.unwrap_or_default(),
5252                    Arc::new(SimpleVariantConflictInvoke),
5253                    Arc::new(StaticWorkerNameGenerator),
5254                );
5255
5256                RibTestDeps {
5257                    component,
5258                    interpreter,
5259                }
5260            }
5261
5262            pub(crate) fn test_deps_with_multiple_interfaces(
5263                rib_input: Option<RibInput>,
5264            ) -> RibTestDeps {
5265                let component = get_metadata_with_multiple_interfaces();
5266                let interpreter = Interpreter::new(
5267                    rib_input.unwrap_or_default(),
5268                    Arc::new(MultiplePackageFunctionInvoke),
5269                    Arc::new(StaticWorkerNameGenerator),
5270                );
5271
5272                RibTestDeps {
5273                    component,
5274                    interpreter,
5275                }
5276            }
5277        }
5278
5279        fn get_component_dependency_with_global_functions() -> ComponentDependency {
5280            let exports = vec![
5281                WitExport::Function(WitFunction {
5282                    name: "add-u32".to_string(),
5283                    parameters: vec![
5284                        WitFunctionParameter {
5285                            name: "param1".to_string(),
5286                            typ: u32(),
5287                        },
5288                        WitFunctionParameter {
5289                            name: "param2".to_string(),
5290                            typ: u32(),
5291                        },
5292                    ],
5293                    result: Some(WitFunctionResult { typ: u32() }),
5294                }),
5295                WitExport::Function(WitFunction {
5296                    name: "add-u64".to_string(),
5297                    parameters: vec![
5298                        WitFunctionParameter {
5299                            name: "param1".to_string(),
5300                            typ: u64(),
5301                        },
5302                        WitFunctionParameter {
5303                            name: "param2".to_string(),
5304                            typ: u64(),
5305                        },
5306                    ],
5307                    result: Some(WitFunctionResult { typ: u64() }),
5308                }),
5309                WitExport::Function(WitFunction {
5310                    name: "add-enum".to_string(),
5311                    parameters: vec![
5312                        WitFunctionParameter {
5313                            name: "param1".to_string(),
5314                            typ: r#enum(&["x", "y", "z"]),
5315                        },
5316                        WitFunctionParameter {
5317                            name: "param2".to_string(),
5318                            typ: r#enum(&["x", "y", "z"]),
5319                        },
5320                    ],
5321                    result: Some(WitFunctionResult {
5322                        typ: r#enum(&["x", "y", "z"]),
5323                    }),
5324                }),
5325                WitExport::Function(WitFunction {
5326                    name: "add-variant".to_string(),
5327                    parameters: vec![
5328                        WitFunctionParameter {
5329                            name: "param1".to_string(),
5330                            typ: get_analysed_type_variant(),
5331                        },
5332                        WitFunctionParameter {
5333                            name: "param2".to_string(),
5334                            typ: get_analysed_type_variant(),
5335                        },
5336                    ],
5337                    result: Some(WitFunctionResult {
5338                        typ: get_analysed_type_variant(),
5339                    }),
5340                }),
5341            ];
5342
5343            let component_info = ComponentDependencyKey {
5344                component_name: "foo".to_string(),
5345                component_id: Uuid::new_v4(),
5346                component_revision: 0,
5347                root_package_name: None,
5348                root_package_version: None,
5349            };
5350
5351            ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
5352        }
5353
5354        struct TestInvoke3;
5355
5356        #[async_trait]
5357        impl RibComponentFunctionInvoke for TestInvoke3 {
5358            async fn invoke(
5359                &self,
5360                _component_dependency: ComponentDependencyKey,
5361                _instruction_id: &InstructionId,
5362                _worker_name: EvaluatedWorkerName,
5363                function_name: EvaluatedFqFn,
5364                args: EvaluatedFnArgs,
5365                _return_type: Option<WitType>,
5366            ) -> RibFunctionInvokeResult {
5367                match function_name.0.as_str() {
5368                    "add-u32" => {
5369                        let args = args.0;
5370                        let arg1 = args[0].get_literal().and_then(|x| x.get_number()).unwrap();
5371                        let arg2 = args[1].get_literal().and_then(|x| x.get_number()).unwrap();
5372                        let result = (arg1 + arg2).unwrap();
5373                        let u32 = result.cast_to(&u32()).unwrap();
5374
5375                        Ok(Some(u32))
5376                    }
5377                    "add-u64" => {
5378                        let args = args.0;
5379                        let arg1 = args[0].get_literal().and_then(|x| x.get_number()).unwrap();
5380                        let arg2 = args[1].get_literal().and_then(|x| x.get_number()).unwrap();
5381                        let result = (arg1 + arg2).unwrap();
5382                        let u64 = result.cast_to(&u64()).unwrap();
5383                        Ok(Some(u64))
5384                    }
5385                    "add-enum" => {
5386                        let args = args.0;
5387                        let arg1 = args[0].clone().value;
5388                        let arg2 = args[1].clone().value;
5389                        match (arg1, arg2) {
5390                            (Value::Enum(x), Value::Enum(y)) => {
5391                                if x == y {
5392                                    let result =
5393                                        ValueAndType::new(Value::Enum(x), r#enum(&["x", "y", "z"]));
5394                                    Ok(Some(result))
5395                                } else {
5396                                    Err(format!("Enums are not equal: {x} and {y}").into())
5397                                }
5398                            }
5399                            (v1, v2) => {
5400                                Err(format!("Invalid arguments for add-enum: {v1:?} and {v2:?}")
5401                                    .into())
5402                            }
5403                        }
5404                    }
5405                    "add-variant" => {
5406                        let args = args.0;
5407                        let arg1 = args[0].clone().value;
5408                        let arg2 = args[1].clone().value;
5409                        match (arg1, arg2) {
5410                            (
5411                                Value::Variant {
5412                                    case_idx: case_idx1,
5413                                    case_value,
5414                                },
5415                                Value::Variant {
5416                                    case_idx: case_idx2,
5417                                    ..
5418                                },
5419                            ) => {
5420                                if case_idx1 == case_idx2 {
5421                                    let result = ValueAndType::new(
5422                                        Value::Variant {
5423                                            case_idx: case_idx1,
5424                                            case_value,
5425                                        },
5426                                        get_analysed_type_variant(),
5427                                    );
5428                                    Ok(Some(result))
5429                                } else {
5430                                    Err(format!(
5431                                        "Variants are not equal: {case_idx1} and {case_idx2}"
5432                                    )
5433                                    .into())
5434                                }
5435                            }
5436                            (v1, v2) => Err(format!(
5437                                "Invalid arguments for add-variant: {v1:?} and {v2:?}"
5438                            )
5439                            .into()),
5440                        }
5441                    }
5442                    fun => Err(format!("unknown function {fun}").into()),
5443                }
5444            }
5445        }
5446    }
5447}