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