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