Skip to main content

rib/interpreter/
rib_interpreter.rs

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