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