1use crate::compiler::byte_code::internal::ExprState;
16use crate::compiler::ir::RibIR;
17use crate::type_inference::TypeHint;
18use crate::{Expr, InferredExpr, InstructionId};
19use std::fmt::{Display, Formatter};
20
21#[derive(Debug, Clone, Default, PartialEq)]
22pub struct RibByteCode {
23 pub instructions: Vec<RibIR>,
24}
25
26#[derive(Debug, Clone, PartialEq)]
27pub enum RibByteCodeGenerationError {
28 CastError(String),
29 AnalysedTypeConversionError(String),
30 PatternMatchDesugarError,
31 RangeSelectionDesugarError(String),
32 UnexpectedTypeError {
33 expected: TypeHint,
34 actual: TypeHint,
35 },
36 UnresolvedWasmComponent {
37 function: String,
38 },
39 UnresolvedWorkerName,
40 UnresolvedResourceVariable,
41}
42
43impl std::error::Error for RibByteCodeGenerationError {}
44
45impl Display for RibByteCodeGenerationError {
46 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
47 match self {
48 RibByteCodeGenerationError::CastError(msg) => write!(f, "cast error: {msg}"),
49 RibByteCodeGenerationError::AnalysedTypeConversionError(msg) => {
50 write!(f, "{msg}")
51 }
52 RibByteCodeGenerationError::PatternMatchDesugarError => {
53 write!(f, "Pattern match desugar error")
54 }
55 RibByteCodeGenerationError::RangeSelectionDesugarError(msg) => {
56 write!(f, "Range selection desugar error: {msg}")
57 }
58 RibByteCodeGenerationError::UnexpectedTypeError { expected, actual } => {
59 write!(
60 f,
61 "Expected type: {}, but got: {}",
62 expected.get_type_kind(),
63 actual.get_type_kind()
64 )
65 }
66 RibByteCodeGenerationError::UnresolvedWasmComponent { function } => {
67 write!(f, "Unresolved wasm component for function: {function}")
68 }
69 RibByteCodeGenerationError::UnresolvedWorkerName => {
70 write!(f, "inline invocation of functions on a worker instance is currently not supported")
71 }
72 _ => {
73 write!(f, "inline invocation of methods on resource constructor instance is currently not supported")
74 }
75 }
76 }
77}
78
79impl RibByteCode {
80 pub fn len(&self) -> usize {
81 self.instructions.len()
82 }
83
84 pub fn is_empty(&self) -> bool {
85 self.instructions.is_empty()
86 }
87
88 pub fn from_expr(
90 inferred_expr: &InferredExpr,
91 ) -> Result<RibByteCode, RibByteCodeGenerationError> {
92 let expr: &Expr = inferred_expr.get_expr();
93 let mut instructions = Vec::new();
94 let mut stack: Vec<ExprState> = Vec::new();
95 let mut instruction_id = InstructionId::init();
96 stack.push(ExprState::from_expr(expr));
97
98 while let Some(remaining) = stack.pop() {
99 match remaining {
100 ExprState::Expr(expr) => {
101 internal::process_expr(
102 &expr,
103 &mut stack,
104 &mut instructions,
105 &mut instruction_id,
106 )?;
107 }
108
109 ExprState::Instruction(instruction) => {
110 instructions.push(instruction);
111 }
112 }
113 }
114
115 Ok(RibByteCode {
117 instructions: instructions.into_iter().rev().collect(),
118 })
119 }
120}
121mod internal {
122 use crate::compiler::desugar::{desugar_pattern_match, desugar_range_selection};
123 use crate::wit_type::{TypeFlags, WitType};
124 use crate::{
125 DynamicParsedFunctionReference, Expr, FunctionReferenceType, InferredType,
126 InstanceIdentifier, InstanceVariable, InstructionId, Range, RibByteCodeGenerationError,
127 RibIR, TypeInternal, VariableId, WitTypeWithUnit,
128 };
129 use std::collections::HashSet;
130
131 use crate::call_type::{CallType, InstanceCreationType};
132 use crate::type_inference::{GetTypeHint, TypeHint};
133 use crate::wit_type::bool;
134 use crate::{IntoValueAndType, Value, ValueAndType};
135 use std::ops::Deref;
136
137 pub(crate) fn process_expr(
138 expr: &Expr,
139 stack: &mut Vec<ExprState>,
140 instructions: &mut Vec<RibIR>,
141 instruction_id: &mut InstructionId,
142 ) -> Result<(), RibByteCodeGenerationError> {
143 match expr {
144 Expr::Unwrap { expr, .. } => {
145 stack.push(ExprState::from_expr(expr.deref()));
146 instructions.push(RibIR::Deconstruct);
147 }
148
149 Expr::GenerateWorkerName { variable_id, .. } => {
150 instructions.push(RibIR::GenerateWorkerName(variable_id.clone()));
151 }
152
153 Expr::Length { expr, .. } => {
154 stack.push(ExprState::from_expr(expr.deref()));
155 instructions.push(RibIR::Length);
156 }
157
158 Expr::Throw { message, .. } => {
159 instructions.push(RibIR::Throw(message.to_string()));
160 }
161 Expr::Identifier { variable_id, .. } => {
162 instructions.push(RibIR::LoadVar(variable_id.clone()));
163 }
164 Expr::Literal { value, .. } => {
165 let value_and_type = value.clone().into_value_and_type();
166 instructions.push(RibIR::PushLit(value_and_type));
167 }
168 Expr::Number {
169 number,
170 inferred_type,
171 ..
172 } => {
173 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
174
175 let value_and_type =
176 number
177 .to_val(&analysed_type)
178 .ok_or(RibByteCodeGenerationError::CastError(format!(
179 "internal error: cannot convert {} to a value of type {}",
180 number.value,
181 analysed_type.get_type_hint()
182 )))?;
183
184 instructions.push(RibIR::PushLit(value_and_type));
185 }
186 Expr::EqualTo { lhs, rhs, .. } => {
187 stack.push(ExprState::from_expr(rhs.deref()));
188 stack.push(ExprState::from_expr(lhs.deref()));
189 instructions.push(RibIR::EqualTo);
190 }
191 Expr::GreaterThan { lhs, rhs, .. } => {
192 stack.push(ExprState::from_expr(rhs.deref()));
193 stack.push(ExprState::from_expr(lhs.deref()));
194 instructions.push(RibIR::GreaterThan);
195 }
196 Expr::LessThan { lhs, rhs, .. } => {
197 stack.push(ExprState::from_expr(rhs.deref()));
198 stack.push(ExprState::from_expr(lhs.deref()));
199 instructions.push(RibIR::LessThan);
200 }
201 Expr::GreaterThanOrEqualTo { lhs, rhs, .. } => {
202 stack.push(ExprState::from_expr(rhs.deref()));
203 stack.push(ExprState::from_expr(lhs.deref()));
204 instructions.push(RibIR::GreaterThanOrEqualTo);
205 }
206 Expr::LessThanOrEqualTo { lhs, rhs, .. } => {
207 stack.push(ExprState::from_expr(rhs.deref()));
208 stack.push(ExprState::from_expr(lhs.deref()));
209 instructions.push(RibIR::LessThanOrEqualTo);
210 }
211 Expr::Plus {
212 lhs,
213 rhs,
214 inferred_type,
215 ..
216 } => {
217 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
218 stack.push(ExprState::from_expr(rhs.deref()));
219 stack.push(ExprState::from_expr(lhs.deref()));
220 instructions.push(RibIR::Plus(analysed_type));
221 }
222 Expr::Minus {
223 lhs,
224 rhs,
225 inferred_type,
226 ..
227 } => {
228 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
229
230 stack.push(ExprState::from_expr(rhs.deref()));
231 stack.push(ExprState::from_expr(lhs.deref()));
232 instructions.push(RibIR::Minus(analysed_type));
233 }
234 Expr::Divide {
235 lhs,
236 rhs,
237 inferred_type,
238 ..
239 } => {
240 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
241
242 stack.push(ExprState::from_expr(rhs.deref()));
243 stack.push(ExprState::from_expr(lhs.deref()));
244 instructions.push(RibIR::Divide(analysed_type));
245 }
246 Expr::Multiply {
247 lhs,
248 rhs,
249 inferred_type,
250 ..
251 } => {
252 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
253
254 stack.push(ExprState::from_expr(rhs.deref()));
255 stack.push(ExprState::from_expr(lhs.deref()));
256 instructions.push(RibIR::Multiply(analysed_type));
257 }
258 Expr::And { lhs, rhs, .. } => {
259 let optimised_expr = Expr::cond(
261 Expr::equal_to(lhs.deref().clone(), Expr::boolean(true)),
262 Expr::equal_to(rhs.deref().clone(), Expr::boolean(true)),
263 Expr::boolean(false),
264 );
265
266 stack.push(ExprState::from_expr(&optimised_expr));
267 }
268
269 Expr::Or { lhs, rhs, .. } => {
270 let optimised_expr = Expr::cond(
271 Expr::equal_to(lhs.deref().clone(), Expr::boolean(true)),
272 Expr::boolean(true),
273 Expr::equal_to(rhs.deref().clone(), Expr::boolean(true)),
274 );
275
276 stack.push(ExprState::from_expr(&optimised_expr));
277 }
278
279 Expr::Record {
280 exprs,
281 inferred_type,
282 ..
283 } => {
284 for (field_name, field_expr) in exprs.iter().rev() {
286 stack.push(ExprState::from_expr(field_expr.as_ref()));
287 instructions.push(RibIR::UpdateRecord(field_name.clone()));
288 }
289 let analysed_type = convert_to_analysed_type(expr, inferred_type);
291 instructions.push(RibIR::CreateAndPushRecord(analysed_type?));
292 }
293 Expr::Sequence {
294 exprs,
295 inferred_type,
296 ..
297 } => {
298 for expr in exprs.iter().rev() {
300 stack.push(ExprState::from_expr(expr));
301 }
302
303 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
304 instructions.push(RibIR::PushList(analysed_type, exprs.len()));
305 }
306 Expr::ExprBlock { exprs, .. } => {
307 for expr in exprs.iter() {
309 stack.push(ExprState::from_expr(expr));
310 }
311 }
312 Expr::Let {
313 variable_id, expr, ..
314 } => {
315 stack.push(ExprState::from_expr(expr.deref()));
316 instructions.push(RibIR::AssignVar(variable_id.clone()));
317 }
318 Expr::PatternMatch {
319 predicate,
320 match_arms,
321 inferred_type,
322 ..
323 } => {
324 let desugared_pattern_match =
325 desugar_pattern_match(predicate.deref(), match_arms, inferred_type.clone())
326 .ok_or(RibByteCodeGenerationError::PatternMatchDesugarError)?;
327
328 stack.push(ExprState::from_expr(&desugared_pattern_match));
329 }
330 Expr::Cond { cond, lhs, rhs, .. } => {
331 handle_if_condition(
332 instruction_id,
333 cond.deref(),
334 lhs.deref(),
335 rhs.deref(),
336 stack,
337 );
338 }
339
340 Expr::SelectField { expr, field, .. } => {
341 stack.push(ExprState::from_expr(expr.deref()));
342 instructions.push(RibIR::SelectField(field.clone()));
343 }
344
345 Expr::SelectIndex { expr, index, .. } => match index.inferred_type().internal_type() {
346 TypeInternal::Range { .. } => {
347 let list_comprehension =
348 desugar_range_selection(expr, index).map_err(|err| {
349 RibByteCodeGenerationError::RangeSelectionDesugarError(format!(
350 "Failed to desugar range selection: {err}"
351 ))
352 })?;
353 stack.push(ExprState::from_expr(&list_comprehension));
354 }
355 _ => {
356 stack.push(ExprState::from_expr(index.deref()));
357 stack.push(ExprState::from_expr(expr.deref()));
358 instructions.push(RibIR::SelectIndexV1);
359 }
360 },
361
362 Expr::Option {
363 expr: Some(inner_expr),
364 inferred_type,
365 ..
366 } => {
367 stack.push(ExprState::from_expr(inner_expr.deref()));
368 instructions.push(RibIR::PushSome(convert_to_analysed_type(
369 expr,
370 inferred_type,
371 )?));
372 }
373
374 Expr::Option { inferred_type, .. } => {
375 let optional = convert_to_analysed_type(expr, inferred_type);
376 instructions.push(RibIR::PushNone(optional.ok()));
377 }
378
379 Expr::Result {
380 expr: Ok(inner_expr),
381 inferred_type,
382 ..
383 } => {
384 stack.push(ExprState::from_expr(inner_expr.deref()));
385 instructions.push(RibIR::PushOkResult(convert_to_analysed_type(
386 expr,
387 inferred_type,
388 )?));
389 }
390
391 Expr::Result {
392 expr: Err(inner_expr),
393 inferred_type,
394 ..
395 } => {
396 stack.push(ExprState::from_expr(inner_expr.deref()));
397 instructions.push(RibIR::PushErrResult(convert_to_analysed_type(
398 expr,
399 inferred_type,
400 )?));
401 }
402
403 Expr::Call {
404 call_type,
405 args,
406 inferred_type,
407 ..
408 } => {
409 match call_type {
412 CallType::Function {
413 function_name,
414 instance_identifier: module,
415 component_info,
416 } => {
417 for expr in args.iter().rev() {
418 stack.push(ExprState::from_expr(expr));
419 }
420
421 let function_result_type = if inferred_type.is_unit() {
422 WitTypeWithUnit::Unit
423 } else {
424 WitTypeWithUnit::Type(convert_to_analysed_type(expr, inferred_type)?)
425 };
426
427 let module = module
428 .as_ref()
429 .expect("Module should be present for function calls");
430
431 let instance_variable = match module.as_ref() {
432 InstanceIdentifier::WitResource { variable_id, .. } => {
433 let variable_id = variable_id.clone().unwrap_or_else(|| {
434 VariableId::global("___STATIC_WIT_RESOURCE".to_string())
435 });
436 InstanceVariable::WitResource(variable_id)
437 }
438 InstanceIdentifier::WitWorker { variable_id, .. } => {
439 let variable_id = variable_id
440 .clone()
441 .ok_or(RibByteCodeGenerationError::UnresolvedWorkerName)?;
442
443 InstanceVariable::WitWorker(variable_id)
444 }
445 };
446
447 let component_info = component_info.as_ref().ok_or(
448 RibByteCodeGenerationError::UnresolvedWasmComponent {
449 function: function_name.to_string(),
450 },
451 )?;
452
453 instructions.push(RibIR::InvokeFunction(
454 component_info.clone(),
455 instance_variable,
456 args.len(),
457 function_result_type,
458 ));
459
460 let site = function_name.site.clone();
461
462 match &function_name.function {
464 DynamicParsedFunctionReference::Function { function } => instructions
465 .push(RibIR::CreateFunctionName(
466 site,
467 FunctionReferenceType::Function {
468 function: function.clone(),
469 },
470 )),
471
472 DynamicParsedFunctionReference::RawResourceConstructor { resource } => {
473 instructions.push(RibIR::CreateFunctionName(
474 site,
475 FunctionReferenceType::RawResourceConstructor {
476 resource: resource.clone(),
477 },
478 ))
479 }
480 DynamicParsedFunctionReference::RawResourceDrop { resource } => {
481 instructions.push(RibIR::CreateFunctionName(
482 site,
483 FunctionReferenceType::RawResourceDrop {
484 resource: resource.clone(),
485 },
486 ))
487 }
488 DynamicParsedFunctionReference::RawResourceMethod {
489 resource,
490 method,
491 } => instructions.push(RibIR::CreateFunctionName(
492 site,
493 FunctionReferenceType::RawResourceMethod {
494 resource: resource.clone(),
495 method: method.clone(),
496 },
497 )),
498 DynamicParsedFunctionReference::RawResourceStaticMethod {
499 resource,
500 method,
501 } => instructions.push(RibIR::CreateFunctionName(
502 site,
503 FunctionReferenceType::RawResourceStaticMethod {
504 resource: resource.clone(),
505 method: method.clone(),
506 },
507 )),
508 }
509 }
510
511 CallType::InstanceCreation(instance_creation_type) => {
517 match instance_creation_type {
518 InstanceCreationType::WitWorker { worker_name, .. } => {
519 if let Some(worker_name) = worker_name {
520 stack.push(ExprState::from_expr(worker_name));
521 } else {
522 for expr in args.iter().rev() {
523 stack.push(ExprState::from_expr(expr));
524 }
525 }
526 }
527
528 InstanceCreationType::WitResource {
529 module,
530 resource_name,
531 component_info,
532 } => {
533 for expr in args.iter().rev() {
534 stack.push(ExprState::from_expr(expr));
535 }
536
537 let module = module
538 .as_ref()
539 .expect("Module should be present for resource calls");
540
541 let instance_variable = match module {
542 InstanceIdentifier::WitResource { variable_id, .. } => {
543 let variable_id = variable_id.as_ref().ok_or({
544 RibByteCodeGenerationError::UnresolvedResourceVariable
545 })?;
546
547 InstanceVariable::WitResource(variable_id.clone())
548 }
549 InstanceIdentifier::WitWorker { variable_id, .. } => {
550 let variable_id = variable_id.as_ref().ok_or({
551 RibByteCodeGenerationError::UnresolvedWorkerName
552 })?;
553
554 InstanceVariable::WitWorker(variable_id.clone())
555 }
556 };
557
558 let site = resource_name.parsed_function_site();
559
560 let component_info = component_info.as_ref().ok_or(
561 RibByteCodeGenerationError::UnresolvedWasmComponent {
562 function: resource_name.resource_name.clone(),
563 },
564 )?;
565
566 let function_result_type = if inferred_type.is_unit() {
567 WitTypeWithUnit::Unit
568 } else {
569 WitTypeWithUnit::Type(convert_to_analysed_type(
570 expr,
571 inferred_type,
572 )?)
573 };
574
575 instructions.push(RibIR::InvokeFunction(
576 component_info.clone(),
577 instance_variable,
578 args.len(),
579 function_result_type,
580 ));
581
582 instructions.push(RibIR::CreateFunctionName(
583 site,
584 FunctionReferenceType::RawResourceConstructor {
585 resource: resource_name.resource_name.clone(),
586 },
587 ));
588 }
589 }
590 }
591
592 CallType::VariantConstructor(variant_name) => {
593 for expr in args.iter().rev() {
594 stack.push(ExprState::from_expr(expr));
595 }
596
597 instructions.push(RibIR::PushVariant(
598 variant_name.clone(),
599 convert_to_analysed_type(expr, inferred_type)?,
600 ));
601 }
602 CallType::EnumConstructor(enum_name) => {
603 for expr in args.iter().rev() {
604 stack.push(ExprState::from_expr(expr));
605 }
606
607 instructions.push(RibIR::PushEnum(
608 enum_name.clone(),
609 convert_to_analysed_type(expr, inferred_type)?,
610 ));
611 }
612 }
613 }
614
615 Expr::Flags {
616 flags,
617 inferred_type,
618 ..
619 } => match inferred_type.internal_type() {
620 TypeInternal::Flags(all_flags) => {
621 let mut bitmap = Vec::new();
622 let flag_values_set: HashSet<&String> = HashSet::from_iter(flags.iter());
623 for flag in all_flags.iter() {
624 bitmap.push(flag_values_set.contains(flag));
625 }
626 instructions.push(RibIR::PushFlag(ValueAndType {
627 value: Value::Flags(bitmap),
628 typ: WitType::Flags(TypeFlags {
629 names: all_flags.iter().map(|n| n.to_string()).collect(),
630 owner: None,
631 name: None,
632 }),
633 }));
634 }
635 _ => {
636 return Err(RibByteCodeGenerationError::UnexpectedTypeError {
637 expected: TypeHint::Flag(Some(flags.clone())),
638 actual: inferred_type.get_type_hint(),
639 });
640 }
641 },
642 Expr::Boolean { value, .. } => {
643 instructions.push(RibIR::PushLit(value.into_value_and_type()));
644 }
645 Expr::GetTag { expr, .. } => {
646 stack.push(ExprState::from_expr(expr.deref()));
647 stack.push(ExprState::from_ir(RibIR::GetTag));
648 }
649
650 Expr::Concat { exprs, .. } => {
651 for expr in exprs.iter().rev() {
652 stack.push(ExprState::from_expr(expr));
653 }
654
655 instructions.push(RibIR::Concat(exprs.len()));
656 }
657
658 Expr::Not { expr, .. } => {
659 stack.push(ExprState::from_expr(expr.deref()));
660 instructions.push(RibIR::Negate);
661 }
662
663 Expr::Tuple {
664 exprs,
665 inferred_type,
666 ..
667 } => {
668 for expr in exprs.iter().rev() {
669 stack.push(ExprState::from_expr(expr));
670 }
671 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
672 instructions.push(RibIR::PushTuple(analysed_type, exprs.len()));
673 }
674
675 Expr::ListComprehension {
676 iterated_variable,
677 iterable_expr,
678 yield_expr,
679 inferred_type,
680 ..
681 } => {
682 let analysed_type = convert_to_analysed_type(expr, inferred_type)?;
683 handle_list_comprehension(
684 instruction_id,
685 stack,
686 iterable_expr,
687 yield_expr,
688 iterated_variable,
689 &analysed_type,
690 )
691 }
692
693 range_expr @ Expr::Range {
694 range,
695 inferred_type,
696 ..
697 } => match inferred_type.internal_type() {
698 TypeInternal::Range { .. } => {
699 let analysed_type = convert_to_analysed_type(range_expr, inferred_type)?;
700
701 handle_range(range, stack, analysed_type, instructions);
702 }
703
704 _ => {
705 return Err(RibByteCodeGenerationError::UnexpectedTypeError {
706 expected: TypeHint::Range,
707 actual: inferred_type.get_type_hint(),
708 });
709 }
710 },
711
712 Expr::InvokeMethodLazy { .. } => {}
714
715 Expr::ListReduce {
716 reduce_variable,
717 iterated_variable,
718 iterable_expr,
719 init_value_expr,
720 yield_expr,
721 ..
722 } => handle_list_reduce(
723 instruction_id,
724 stack,
725 reduce_variable,
726 iterated_variable,
727 iterable_expr,
728 init_value_expr,
729 yield_expr,
730 ),
731 }
732
733 Ok(())
734 }
735
736 pub(crate) fn convert_to_analysed_type(
737 expr: &Expr,
738 inferred_type: &InferredType,
739 ) -> Result<WitType, RibByteCodeGenerationError> {
740 WitType::try_from(inferred_type).map_err(|error| {
741 RibByteCodeGenerationError::AnalysedTypeConversionError(format!(
742 "Invalid Rib {}. Error converting {} to WitType: {}",
743 expr,
744 inferred_type.get_type_hint(),
745 error
746 ))
747 })
748 }
749
750 pub(crate) enum ExprState {
755 Expr(Expr),
756 Instruction(RibIR),
757 }
758
759 impl ExprState {
760 pub(crate) fn from_expr(expr: &Expr) -> Self {
761 ExprState::Expr(expr.clone())
762 }
763
764 pub(crate) fn from_ir(ir: RibIR) -> Self {
765 ExprState::Instruction(ir)
766 }
767 }
768
769 fn handle_range(
770 range: &Range,
771 stack: &mut Vec<ExprState>,
772 analysed_type: WitType,
773 instructions: &mut Vec<RibIR>,
774 ) {
775 let from = range.from();
776 let to = range.to();
777 let inclusive = range.inclusive();
778
779 if let Some(from) = from {
780 stack.push(ExprState::from_expr(from));
781 instructions.push(RibIR::UpdateRecord("from".to_string()));
782 }
783
784 if let Some(to) = to {
785 stack.push(ExprState::from_expr(to));
786 instructions.push(RibIR::UpdateRecord("to".to_string()));
787 }
788
789 stack.push(ExprState::from_ir(RibIR::PushLit(ValueAndType::new(
790 Value::Bool(inclusive),
791 bool(),
792 ))));
793
794 instructions.push(RibIR::UpdateRecord("inclusive".to_string()));
795
796 instructions.push(RibIR::CreateAndPushRecord(analysed_type));
797 }
798
799 fn handle_list_comprehension(
800 instruction_id: &mut InstructionId,
801 stack: &mut Vec<ExprState>,
802 iterable_expr: &Expr,
803 yield_expr: &Expr,
804 variable_id: &VariableId,
805 sink_type: &WitType,
806 ) {
807 stack.push(ExprState::from_expr(iterable_expr));
808
809 stack.push(ExprState::from_ir(RibIR::ToIterator));
810
811 stack.push(ExprState::from_ir(RibIR::CreateSink(sink_type.clone())));
812
813 let loop_start_label = instruction_id.increment_mut();
814
815 stack.push(ExprState::from_ir(RibIR::Label(loop_start_label.clone())));
816
817 let exit_label = instruction_id.increment_mut();
818
819 stack.push(ExprState::from_ir(RibIR::IsEmpty));
820
821 stack.push(ExprState::from_ir(RibIR::JumpIfFalse(exit_label.clone())));
822
823 stack.push(ExprState::from_ir(RibIR::AdvanceIterator));
824
825 stack.push(ExprState::from_ir(RibIR::AssignVar(variable_id.clone())));
826
827 stack.push(ExprState::from_expr(yield_expr));
828
829 stack.push(ExprState::from_ir(RibIR::PushToSink));
830
831 stack.push(ExprState::from_ir(RibIR::Jump(loop_start_label)));
832
833 stack.push(ExprState::from_ir(RibIR::Label(exit_label)));
834
835 stack.push(ExprState::from_ir(RibIR::SinkToList))
836 }
837
838 fn handle_list_reduce(
839 instruction_id: &mut InstructionId,
840 stack: &mut Vec<ExprState>,
841 reduce_variable: &VariableId,
842 iterated_variable: &VariableId,
843 iterable_expr: &Expr,
844 initial_value_expr: &Expr,
845 yield_expr: &Expr,
846 ) {
847 stack.push(ExprState::from_expr(iterable_expr));
848
849 stack.push(ExprState::from_expr(initial_value_expr));
850
851 stack.push(ExprState::from_ir(RibIR::AssignVar(
852 reduce_variable.clone(),
853 )));
854
855 stack.push(ExprState::from_ir(RibIR::ToIterator));
856
857 let loop_start_label = instruction_id.increment_mut();
858
859 stack.push(ExprState::from_ir(RibIR::Label(loop_start_label.clone())));
860
861 let exit_label = instruction_id.increment_mut();
862
863 stack.push(ExprState::from_ir(RibIR::IsEmpty));
864
865 stack.push(ExprState::from_ir(RibIR::JumpIfFalse(exit_label.clone())));
866
867 stack.push(ExprState::from_ir(RibIR::AdvanceIterator));
868
869 stack.push(ExprState::from_ir(RibIR::AssignVar(
870 iterated_variable.clone(),
871 )));
872
873 stack.push(ExprState::from_expr(yield_expr));
874
875 stack.push(ExprState::from_ir(RibIR::AssignVar(
876 reduce_variable.clone(),
877 )));
878
879 stack.push(ExprState::from_ir(RibIR::Jump(loop_start_label)));
880
881 stack.push(ExprState::from_ir(RibIR::Label(exit_label)));
882
883 stack.push(ExprState::from_ir(RibIR::LoadVar(reduce_variable.clone())))
884 }
885
886 fn handle_if_condition(
887 instruction_id: &mut InstructionId,
888 if_expr: &Expr,
889 then_expr: &Expr,
890 else_expr: &Expr,
891 stack: &mut Vec<ExprState>,
892 ) {
893 instruction_id.increment_mut();
894 let else_beginning_id = instruction_id.clone();
895 instruction_id.increment_mut();
896 let else_ending_id = instruction_id.clone();
897
898 stack.push(ExprState::from_expr(if_expr));
899
900 stack.push(ExprState::from_ir(RibIR::JumpIfFalse(
901 else_beginning_id.clone(),
902 )));
903
904 stack.push(ExprState::from_expr(then_expr));
905
906 stack.push(ExprState::from_ir(RibIR::Jump(else_ending_id.clone())));
907
908 stack.push(ExprState::from_ir(RibIR::Label(else_beginning_id.clone())));
909
910 stack.push(ExprState::from_expr(else_expr));
911
912 stack.push(ExprState::from_ir(RibIR::Label(else_ending_id.clone())));
913 }
914}
915
916#[cfg(test)]
917mod compiler_tests {
918 use bigdecimal::BigDecimal;
919 use test_r::test;
920
921 use super::*;
922 use crate::wit_type::builders as wit_type;
923 use crate::wit_type::{field, list, record, s32, str};
924 use crate::{ArmPattern, InferredType, MatchArm, RibCompiler, VariableId};
925 use crate::{IntoValueAndType, Value, ValueAndType};
926
927 #[test]
928 fn test_instructions_for_literal() {
929 let literal = Expr::literal("hello");
930
931 let compiler = RibCompiler::default();
932
933 let compiler_output = compiler.compile(literal).unwrap();
934
935 let instruction_set = vec![RibIR::PushLit("hello".into_value_and_type())];
936
937 let expected_instructions = RibByteCode {
938 instructions: instruction_set,
939 };
940
941 assert_eq!(compiler_output.byte_code, expected_instructions);
942 }
943
944 #[test]
945 fn test_instructions_for_identifier() {
946 let inferred_input_type = InferredType::string();
947
948 let variable_id = VariableId::local("request", 0);
949
950 let expr = Expr::identifier_with_variable_id(variable_id.clone(), None)
951 .with_inferred_type(inferred_input_type);
952
953 let compiler = RibCompiler::default();
954
955 let inferred_expr = compiler.infer_types(expr).unwrap();
956
957 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
958
959 let instruction_set = vec![RibIR::LoadVar(variable_id)];
960
961 let expected_instructions = RibByteCode {
962 instructions: instruction_set,
963 };
964
965 assert_eq!(instructions, expected_instructions);
966 }
967
968 #[test]
969 fn test_instructions_assign_variable() {
970 let literal = Expr::literal("hello");
971
972 let variable_id = VariableId::local("request", 0);
973
974 let expr = Expr::let_binding_with_variable_id(variable_id.clone(), literal, None);
975
976 let compiler = RibCompiler::default();
977
978 let inferred_expr = compiler.infer_types(expr).unwrap();
979
980 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
981
982 let instruction_set = vec![
983 RibIR::PushLit("hello".into_value_and_type()),
984 RibIR::AssignVar(variable_id),
985 ];
986
987 let expected_instructions = RibByteCode {
988 instructions: instruction_set,
989 };
990
991 assert_eq!(instructions, expected_instructions);
992 }
993
994 #[test]
995 fn test_instructions_equal_to() {
996 let number_f32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::f32());
997
998 let number_u32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::u32());
999
1000 let expr = Expr::equal_to(number_f32, number_u32);
1001
1002 let compiler = RibCompiler::default();
1003
1004 let inferred_expr = compiler.infer_types(expr).unwrap();
1005
1006 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1007
1008 let value_and_type1 = 1.0f32.into_value_and_type();
1009
1010 let value_and_type2 = 1u32.into_value_and_type();
1011
1012 let instruction_set = vec![
1013 RibIR::PushLit(value_and_type2),
1014 RibIR::PushLit(value_and_type1),
1015 RibIR::EqualTo,
1016 ];
1017
1018 let expected_instructions = RibByteCode {
1019 instructions: instruction_set,
1020 };
1021
1022 assert_eq!(instructions, expected_instructions);
1023 }
1024
1025 #[test]
1026 fn test_instructions_greater_than() {
1027 let number_f32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::f32());
1028
1029 let number_u32 = Expr::number_inferred(BigDecimal::from(2), None, InferredType::u32());
1030
1031 let expr = Expr::greater_than(number_f32, number_u32);
1032
1033 let compiler = RibCompiler::default();
1034
1035 let inferred_expr = compiler.infer_types(expr).unwrap();
1036
1037 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1038
1039 let value_and_type1 = 1.0f32.into_value_and_type();
1040
1041 let value_and_type2 = 2u32.into_value_and_type();
1042
1043 let instruction_set = vec![
1044 RibIR::PushLit(value_and_type2),
1045 RibIR::PushLit(value_and_type1),
1046 RibIR::GreaterThan,
1047 ];
1048
1049 let expected_instructions = RibByteCode {
1050 instructions: instruction_set,
1051 };
1052
1053 assert_eq!(instructions, expected_instructions);
1054 }
1055
1056 #[test]
1057 fn test_instructions_less_than() {
1058 let number_f32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::f32());
1059
1060 let number_u32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::u32());
1061
1062 let expr = Expr::less_than(number_f32, number_u32);
1063
1064 let compiler = RibCompiler::default();
1065
1066 let inferred_expr = compiler.infer_types(expr).unwrap();
1067
1068 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1069
1070 let value_and_type1 = 1.0f32.into_value_and_type();
1071
1072 let value_and_type2 = 1u32.into_value_and_type();
1073
1074 let instruction_set = vec![
1075 RibIR::PushLit(value_and_type2),
1076 RibIR::PushLit(value_and_type1),
1077 RibIR::LessThan,
1078 ];
1079
1080 let expected_instructions = RibByteCode {
1081 instructions: instruction_set,
1082 };
1083
1084 assert_eq!(instructions, expected_instructions);
1085 }
1086
1087 #[test]
1088 fn test_instructions_greater_than_or_equal_to() {
1089 let number_f32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::f32());
1090
1091 let number_u32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::u32());
1092
1093 let expr = Expr::greater_than_or_equal_to(number_f32, number_u32);
1094
1095 let compiler = RibCompiler::default();
1096
1097 let inferred_expr = compiler.infer_types(expr).unwrap();
1098
1099 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1100
1101 let value_and_type1 = 1.0f32.into_value_and_type();
1102
1103 let value_and_type2 = 1u32.into_value_and_type();
1104
1105 let instruction_set = vec![
1106 RibIR::PushLit(value_and_type2),
1107 RibIR::PushLit(value_and_type1),
1108 RibIR::GreaterThanOrEqualTo,
1109 ];
1110
1111 let expected_instructions = RibByteCode {
1112 instructions: instruction_set,
1113 };
1114
1115 assert_eq!(instructions, expected_instructions);
1116 }
1117
1118 #[test]
1119 fn test_instructions_less_than_or_equal_to() {
1120 let number_f32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::f32());
1121
1122 let number_u32 = Expr::number_inferred(BigDecimal::from(1), None, InferredType::u32());
1123
1124 let expr = Expr::less_than_or_equal_to(number_f32, number_u32);
1125
1126 let compiler = RibCompiler::default();
1127
1128 let inferred_expr = compiler.infer_types(expr).unwrap();
1129
1130 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1131
1132 let value_and_type1 = 1.0f32.into_value_and_type();
1133
1134 let value_and_type2 = 1u32.into_value_and_type();
1135
1136 let instruction_set = vec![
1137 RibIR::PushLit(value_and_type2),
1138 RibIR::PushLit(value_and_type1),
1139 RibIR::LessThanOrEqualTo,
1140 ];
1141
1142 let expected_instructions = RibByteCode {
1143 instructions: instruction_set,
1144 };
1145
1146 assert_eq!(instructions, expected_instructions);
1147 }
1148
1149 #[test]
1150 fn test_instructions_for_record() {
1151 let expr = Expr::record(vec![
1152 ("foo_key".to_string(), Expr::literal("foo_value")),
1153 ("bar_key".to_string(), Expr::literal("bar_value")),
1154 ])
1155 .with_inferred_type(InferredType::record(vec![
1156 (String::from("foo_key"), InferredType::string()),
1157 (String::from("bar_key"), InferredType::string()),
1158 ]));
1159
1160 let compiler = RibCompiler::default();
1161
1162 let inferred_expr = compiler.infer_types(expr).unwrap();
1163
1164 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1165
1166 let bar_value = "bar_value".into_value_and_type();
1167
1168 let foo_value = "foo_value".into_value_and_type();
1169
1170 let instruction_set = vec![
1171 RibIR::PushLit(bar_value),
1172 RibIR::PushLit(foo_value),
1173 RibIR::CreateAndPushRecord(record(vec![
1174 field("foo_key", str()),
1175 field("bar_key", str()),
1176 ])),
1177 RibIR::UpdateRecord("foo_key".to_string()),
1178 RibIR::UpdateRecord("bar_key".to_string()),
1179 ];
1180
1181 let expected_instructions = RibByteCode {
1182 instructions: instruction_set,
1183 };
1184
1185 assert_eq!(instructions, expected_instructions);
1186 }
1187
1188 #[test]
1189 fn test_instructions_for_multiple() {
1190 let expr = Expr::expr_block(vec![Expr::literal("foo"), Expr::literal("bar")]);
1191
1192 let compiler = RibCompiler::default();
1193
1194 let inferred_expr = compiler.infer_types(expr).unwrap();
1195
1196 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1197
1198 let instruction_set = vec![
1199 RibIR::PushLit("foo".into_value_and_type()),
1200 RibIR::PushLit("bar".into_value_and_type()),
1201 ];
1202
1203 let expected_instructions = RibByteCode {
1204 instructions: instruction_set,
1205 };
1206
1207 assert_eq!(instructions, expected_instructions);
1208 }
1209
1210 #[test]
1211 fn test_instructions_if_conditional() {
1212 let if_expr = Expr::literal("pred").with_inferred_type(InferredType::bool());
1213
1214 let then_expr = Expr::literal("then");
1215
1216 let else_expr = Expr::literal("else");
1217
1218 let expr =
1219 Expr::cond(if_expr, then_expr, else_expr).with_inferred_type(InferredType::string());
1220
1221 let compiler = RibCompiler::default();
1222
1223 let inferred_expr = compiler.infer_types(expr).unwrap();
1224
1225 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1226
1227 let instruction_set = vec![
1228 RibIR::PushLit("pred".into_value_and_type()),
1229 RibIR::JumpIfFalse(InstructionId { index: 1 }), RibIR::PushLit("then".into_value_and_type()),
1231 RibIR::Jump(InstructionId { index: 2 }), RibIR::Label(InstructionId { index: 1 }),
1233 RibIR::PushLit("else".into_value_and_type()),
1234 RibIR::Label(InstructionId { index: 2 }),
1235 ];
1236
1237 let expected_instructions = RibByteCode {
1238 instructions: instruction_set,
1239 };
1240
1241 assert_eq!(instructions, expected_instructions);
1242 }
1243
1244 #[test]
1245 fn test_instructions_for_nested_if_else() {
1246 let if_expr = Expr::literal("if-pred1").with_inferred_type(InferredType::bool());
1247
1248 let then_expr = Expr::literal("then1").with_inferred_type(InferredType::string());
1249
1250 let else_expr = Expr::cond(
1251 Expr::literal("else-pred2").with_inferred_type(InferredType::bool()),
1252 Expr::literal("else-then2"),
1253 Expr::literal("else-else2"),
1254 )
1255 .with_inferred_type(InferredType::string());
1256
1257 let expr =
1258 Expr::cond(if_expr, then_expr, else_expr).with_inferred_type(InferredType::string());
1259
1260 let compiler = RibCompiler::default();
1261
1262 let inferred_expr = compiler.infer_types(expr).unwrap();
1263
1264 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1265
1266 let instruction_set = vec![
1267 RibIR::PushLit("if-pred1".into_value_and_type()),
1269 RibIR::JumpIfFalse(InstructionId { index: 1 }), RibIR::PushLit("then1".into_value_and_type()),
1271 RibIR::Jump(InstructionId { index: 2 }), RibIR::Label(InstructionId { index: 1 }),
1273 RibIR::PushLit("else-pred2".into_value_and_type()),
1274 RibIR::JumpIfFalse(InstructionId { index: 3 }), RibIR::PushLit("else-then2".into_value_and_type()),
1276 RibIR::Jump(InstructionId { index: 4 }), RibIR::Label(InstructionId { index: 3 }),
1278 RibIR::PushLit("else-else2".into_value_and_type()),
1279 RibIR::Label(InstructionId { index: 4 }),
1280 RibIR::Label(InstructionId { index: 2 }),
1281 ];
1282
1283 let expected_instructions = RibByteCode {
1284 instructions: instruction_set,
1285 };
1286
1287 assert_eq!(instructions, expected_instructions);
1288 }
1289
1290 #[test]
1291 fn test_instructions_for_select_field() {
1292 let record = Expr::record(vec![
1293 ("foo_key".to_string(), Expr::literal("foo_value")),
1294 ("bar_key".to_string(), Expr::literal("bar_value")),
1295 ])
1296 .with_inferred_type(InferredType::record(vec![
1297 (String::from("foo_key"), InferredType::string()),
1298 (String::from("bar_key"), InferredType::string()),
1299 ]));
1300
1301 let expr =
1302 Expr::select_field(record, "bar_key", None).with_inferred_type(InferredType::string());
1303
1304 let compiler = RibCompiler::default();
1305
1306 let inferred_expr = compiler.infer_types(expr).unwrap();
1307
1308 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1309
1310 let bar_value = "bar_value".into_value_and_type();
1311
1312 let foo_value = "foo_value".into_value_and_type();
1313
1314 let instruction_set = vec![
1315 RibIR::PushLit(bar_value),
1316 RibIR::PushLit(foo_value),
1317 RibIR::CreateAndPushRecord(wit_type::record(vec![
1318 field("bar_key", str()),
1319 field("foo_key", str()),
1320 ])),
1321 RibIR::UpdateRecord("foo_key".to_string()), RibIR::UpdateRecord("bar_key".to_string()), RibIR::SelectField("bar_key".to_string()),
1324 ];
1325
1326 let expected_instructions = RibByteCode {
1327 instructions: instruction_set,
1328 };
1329
1330 assert_eq!(instructions, expected_instructions);
1331 }
1332
1333 #[test]
1334 fn test_instructions_for_select_index() {
1335 let sequence = Expr::sequence(vec![Expr::literal("foo"), Expr::literal("bar")], None)
1336 .with_inferred_type(InferredType::list(InferredType::string()));
1337
1338 let expr = Expr::select_index(sequence, Expr::number(BigDecimal::from(1)))
1339 .with_inferred_type(InferredType::string());
1340
1341 let compiler = RibCompiler::default();
1342
1343 let inferred_expr = compiler.infer_types(expr).unwrap();
1344
1345 let instructions = RibByteCode::from_expr(&inferred_expr).unwrap();
1346
1347 let instruction_set = vec![
1348 RibIR::PushLit(ValueAndType::new(Value::S32(1), s32())),
1349 RibIR::PushLit("bar".into_value_and_type()),
1350 RibIR::PushLit("foo".into_value_and_type()),
1351 RibIR::PushList(list(str()), 2),
1352 RibIR::SelectIndexV1,
1353 ];
1354
1355 let expected_instructions = RibByteCode {
1356 instructions: instruction_set,
1357 };
1358
1359 assert_eq!(instructions, expected_instructions);
1360 }
1361
1362 #[test]
1363 fn test_instructions_for_expr_arm_pattern_match() {
1364 let expr = Expr::pattern_match(
1365 Expr::literal("pred"),
1366 vec![
1367 MatchArm::new(
1368 ArmPattern::Literal(Box::new(Expr::literal("arm1_pattern_expr"))),
1369 Expr::literal("arm1_resolution_expr"),
1370 ),
1371 MatchArm::new(
1372 ArmPattern::Literal(Box::new(Expr::literal("arm2_pattern_expr"))),
1373 Expr::literal("arm2_resolution_expr"),
1374 ),
1375 MatchArm::new(
1376 ArmPattern::Literal(Box::new(Expr::literal("arm3_pattern_expr"))),
1377 Expr::literal("arm3_resolution_expr"),
1378 ),
1379 ],
1380 )
1381 .with_inferred_type(InferredType::string());
1382
1383 let rib_compiler = RibCompiler::default();
1384
1385 let instructions = rib_compiler.compile(expr).unwrap().byte_code;
1386
1387 let instruction_set = vec![
1389 RibIR::PushLit("arm1_pattern_expr".into_value_and_type()),
1390 RibIR::PushLit("pred".into_value_and_type()),
1391 RibIR::EqualTo,
1392 RibIR::JumpIfFalse(InstructionId { index: 1 }),
1393 RibIR::PushLit("arm1_resolution_expr".into_value_and_type()),
1394 RibIR::Jump(InstructionId { index: 2 }),
1395 RibIR::Label(InstructionId { index: 1 }),
1396 RibIR::PushLit("arm2_pattern_expr".into_value_and_type()),
1397 RibIR::PushLit("pred".into_value_and_type()),
1398 RibIR::EqualTo,
1399 RibIR::JumpIfFalse(InstructionId { index: 3 }),
1400 RibIR::PushLit("arm2_resolution_expr".into_value_and_type()),
1401 RibIR::Jump(InstructionId { index: 4 }),
1402 RibIR::Label(InstructionId { index: 3 }),
1403 RibIR::PushLit("arm3_pattern_expr".into_value_and_type()),
1404 RibIR::PushLit("pred".into_value_and_type()),
1405 RibIR::EqualTo,
1406 RibIR::JumpIfFalse(InstructionId { index: 5 }),
1407 RibIR::PushLit("arm3_resolution_expr".into_value_and_type()),
1408 RibIR::Jump(InstructionId { index: 6 }),
1409 RibIR::Label(InstructionId { index: 5 }),
1410 RibIR::Throw("No match found".to_string()),
1411 RibIR::Label(InstructionId { index: 6 }),
1412 RibIR::Label(InstructionId { index: 4 }),
1413 RibIR::Label(InstructionId { index: 2 }),
1414 ];
1415
1416 let expected_instructions = RibByteCode {
1417 instructions: instruction_set,
1418 };
1419
1420 assert_eq!(instructions, expected_instructions);
1421 }
1422
1423 #[cfg(test)]
1424 mod invalid_function_invoke_tests {
1425 use test_r::test;
1426
1427 use crate::compiler::byte_code::compiler_tests::internal;
1428 use crate::wit_type::str;
1429 use crate::{Expr, RibCompiler, RibCompilerConfig};
1430
1431 #[test]
1432 fn test_unknown_function() {
1433 let expr = r#"
1434 foo(request);
1435 "success"
1436 "#;
1437
1438 let expr = Expr::from_text(expr).unwrap();
1439 let compiler = RibCompiler::default();
1440
1441 let compiler_error = compiler.compile(expr).unwrap_err().to_string();
1442
1443 assert_eq!(compiler_error, "error in the following rib found at line 2, column 16\n`foo(request)`\ncause: invalid function call `foo`\nunknown function\n");
1444 }
1445
1446 #[test]
1447 fn test_invalid_arg_size_function() {
1448 let metadata = internal::get_component_metadata("foo", vec![str()], str());
1449
1450 let expr = r#"
1451 let user_id = "user";
1452 let result = foo(user_id, user_id);
1453 result
1454 "#;
1455
1456 let expr = Expr::from_text(expr).unwrap();
1457
1458 let compiler_config = RibCompilerConfig::new(metadata, vec![], vec![]);
1459
1460 let compiler = RibCompiler::new(compiler_config);
1461
1462 let compiler_error = compiler.compile(expr).unwrap_err().to_string();
1463 assert_eq!(
1464 compiler_error,
1465 "error in the following rib found at line 3, column 29\n`foo(user_id, user_id)`\ncause: invalid argument size for function `foo`. expected 1 arguments, found 2\n"
1466 );
1467 }
1468
1469 #[test]
1470 fn test_invalid_arg_types_function() {
1471 let metadata = internal::get_component_metadata("foo", vec![str()], str());
1472
1473 let expr = r#"
1474 let result = foo(1u64);
1475 result
1476 "#;
1477
1478 let expr = Expr::from_text(expr).unwrap();
1479
1480 let compiler_config = RibCompilerConfig::new(metadata, vec![], vec![]);
1481
1482 let compiler = RibCompiler::new(compiler_config);
1483
1484 let compiler_error = compiler.compile(expr).unwrap_err().to_string();
1485 assert_eq!(
1486 compiler_error,
1487 "error in the following rib found at line 2, column 33\n`1: u64`\ncause: type mismatch. expected string, found u64\ninvalid argument to the function `foo`\n"
1488 );
1489 }
1490
1491 #[test]
1492 fn test_invalid_arg_types_variants() {
1493 let metadata = internal::metadata_with_variants();
1494
1495 let expr = r#"
1496 let regiser_user_action = register-user("foo");
1497 let result = golem:it/api.{foo}(regiser_user_action);
1498 result
1499 "#;
1500
1501 let expr = Expr::from_text(expr).unwrap();
1502
1503 let compiler_config = RibCompilerConfig::new(metadata, vec![], vec![]);
1504
1505 let compiler = RibCompiler::new(compiler_config);
1506
1507 let compiler_error = compiler.compile(expr).unwrap_err().to_string();
1508 assert_eq!(
1509 compiler_error,
1510 "error in the following rib found at line 2, column 56\n`\"foo\"`\ncause: type mismatch. expected u64, found string\ninvalid argument to the function `register-user`\n"
1511 );
1512 }
1513 }
1514
1515 #[cfg(test)]
1516 mod global_input_tests {
1517 use test_r::test;
1518
1519 use crate::compiler::byte_code::compiler_tests::internal;
1520 use crate::wit_type::{
1521 case, field, list, option, r#enum, record, result, str, tuple, u32, u64, unit_case,
1522 variant,
1523 };
1524 use crate::{Expr, RibCompiler, RibCompilerConfig};
1525
1526 #[test]
1527 async fn test_str_global_input() {
1528 let request_value_type = str();
1529
1530 let output_analysed_type = str();
1531
1532 let analysed_exports = internal::get_component_metadata(
1533 "my-worker-function",
1534 vec![request_value_type.clone()],
1535 output_analysed_type,
1536 );
1537
1538 let expr = r#"
1539 let x = request;
1540 let worker = instance();
1541 worker.my-worker-function(x);
1542 match x {
1543 "foo" => "success",
1544 _ => "fallback"
1545 }
1546 "#;
1547
1548 let expr = Expr::from_text(expr).unwrap();
1549 let compiler =
1550 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1551 let compiled = compiler.compile(expr).unwrap();
1552 let expected_type_info =
1553 internal::rib_input_type_info(vec![("request", request_value_type)]);
1554
1555 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1556 }
1557
1558 #[test]
1559 async fn test_number_global_input() {
1560 let request_value_type = u32();
1561
1562 let output_analysed_type = str();
1563
1564 let analysed_exports = internal::get_component_metadata(
1565 "my-worker-function",
1566 vec![request_value_type.clone()],
1567 output_analysed_type,
1568 );
1569
1570 let expr = r#"
1571 let x = request;
1572 let worker = instance();
1573 worker.my-worker-function(x);
1574 match x {
1575 1 => "success",
1576 0 => "failure"
1577 }
1578 "#;
1579
1580 let expr = Expr::from_text(expr).unwrap();
1581 let compiler =
1582 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1583 let compiled = compiler.compile(expr).unwrap();
1584 let expected_type_info =
1585 internal::rib_input_type_info(vec![("request", request_value_type)]);
1586
1587 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1588 }
1589
1590 #[test]
1591 async fn test_variant_type_info() {
1592 let request_value_type = variant(vec![
1593 case("register-user", u64()),
1594 case("process-user", str()),
1595 unit_case("validate"),
1596 ]);
1597
1598 let output_analysed_type = str();
1599
1600 let analysed_exports = internal::get_component_metadata(
1601 "my-worker-function",
1602 vec![request_value_type.clone()],
1603 output_analysed_type,
1604 );
1605
1606 let expr = r#"
1613 let worker = instance();
1614 worker.my-worker-function(request);
1615 match request {
1616 process-user(user) => user,
1617 _ => "default"
1618 }
1619 "#;
1620
1621 let expr = Expr::from_text(expr).unwrap();
1622 let compiler =
1623 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1624 let compiled = compiler.compile(expr).unwrap();
1625 let expected_type_info =
1626 internal::rib_input_type_info(vec![("request", request_value_type)]);
1627
1628 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1629 }
1630
1631 #[test]
1632 async fn test_result_type_info() {
1633 let request_value_type = result(u64(), str());
1634
1635 let output_analysed_type = str();
1636
1637 let analysed_exports = internal::get_component_metadata(
1638 "my-worker-function",
1639 vec![request_value_type.clone()],
1640 output_analysed_type,
1641 );
1642
1643 let expr = r#"
1650 let worker = instance();
1651 worker.my-worker-function(request);
1652 match request {
1653 ok(x) => "${x}",
1654 err(msg) => msg
1655 }
1656 "#;
1657
1658 let expr = Expr::from_text(expr).unwrap();
1659 let compiler =
1660 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1661 let compiled = compiler.compile(expr).unwrap();
1662 let expected_type_info =
1663 internal::rib_input_type_info(vec![("request", request_value_type)]);
1664
1665 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1666 }
1667
1668 #[test]
1669 async fn test_option_type_info() {
1670 let request_value_type = option(str());
1671
1672 let output_analysed_type = str();
1673
1674 let analysed_exports = internal::get_component_metadata(
1675 "my-worker-function",
1676 vec![request_value_type.clone()],
1677 output_analysed_type,
1678 );
1679
1680 let expr = r#"
1687 let worker = instance();
1688 worker.my-worker-function(request);
1689 match request {
1690 some(x) => x,
1691 none => "error"
1692 }
1693 "#;
1694
1695 let expr = Expr::from_text(expr).unwrap();
1696 let compiler =
1697 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1698 let compiled = compiler.compile(expr).unwrap();
1699 let expected_type_info =
1700 internal::rib_input_type_info(vec![("request", request_value_type)]);
1701
1702 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1703 }
1704
1705 #[test]
1706 async fn test_enum_type_info() {
1707 let request_value_type = r#enum(&["prod", "dev", "test"]);
1708 let output_analysed_type = str();
1709
1710 let analysed_exports = internal::get_component_metadata(
1711 "my-worker-function",
1712 vec![request_value_type.clone()],
1713 output_analysed_type,
1714 );
1715
1716 let expr = r#"
1723 let worker = instance();
1724 worker.my-worker-function(request);
1725 match request {
1726 prod => "p",
1727 dev => "d",
1728 test => "t"
1729 }
1730 "#;
1731
1732 let expr = Expr::from_text(expr).unwrap();
1733 let compiler =
1734 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1735 let compiled = compiler.compile(expr).unwrap();
1736 let expected_type_info =
1737 internal::rib_input_type_info(vec![("request", request_value_type)]);
1738
1739 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1740 }
1741
1742 #[test]
1743 async fn test_record_global_input() {
1744 let request_value_type =
1745 record(vec![field("path", record(vec![field("user", str())]))]);
1746
1747 let output_analysed_type = str();
1748
1749 let analysed_exports = internal::get_component_metadata(
1750 "my-worker-function",
1751 vec![request_value_type.clone()],
1752 output_analysed_type,
1753 );
1754
1755 let expr = r#"
1762 let x = request;
1763 let worker = instance();
1764 worker.my-worker-function(x);
1765
1766 let name = x.path.user;
1767
1768 match x {
1769 { path : { user : some_name } } => some_name,
1770 _ => name
1771 }
1772 "#;
1773
1774 let expr = Expr::from_text(expr).unwrap();
1775 let compiler =
1776 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1777 let compiled = compiler.compile(expr).unwrap();
1778 let expected_type_info =
1779 internal::rib_input_type_info(vec![("request", request_value_type)]);
1780
1781 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1782 }
1783
1784 #[test]
1785 async fn test_tuple_global_input() {
1786 let request_value_type = tuple(vec![str(), u32(), record(vec![field("user", str())])]);
1787
1788 let output_analysed_type = str();
1789
1790 let analysed_exports = internal::get_component_metadata(
1791 "my-worker-function",
1792 vec![request_value_type.clone()],
1793 output_analysed_type,
1794 );
1795
1796 let expr = r#"
1801 let x = request;
1802 let worker = instance();
1803 worker.my-worker-function(x);
1804 match x {
1805 (_, _, record) => record.user,
1806 _ => "fallback"
1807 }
1808 "#;
1809
1810 let expr = Expr::from_text(expr).unwrap();
1811 let compiler =
1812 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1813 let compiled = compiler.compile(expr).unwrap();
1814 let expected_type_info =
1815 internal::rib_input_type_info(vec![("request", request_value_type)]);
1816
1817 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1818 }
1819
1820 #[test]
1821 async fn test_list_global_input() {
1822 let request_value_type = list(str());
1823
1824 let output_analysed_type = str();
1825
1826 let analysed_exports = internal::get_component_metadata(
1827 "my-worker-function",
1828 vec![request_value_type.clone()],
1829 output_analysed_type,
1830 );
1831
1832 let expr = r#"
1837 let x = request;
1838 let worker = instance();
1839 worker.my-worker-function(x);
1840 match x {
1841 [a, b, c] => a,
1842 _ => "fallback"
1843 }
1844 "#;
1845
1846 let expr = Expr::from_text(expr).unwrap();
1847 let compiler =
1848 RibCompiler::new(RibCompilerConfig::new(analysed_exports, vec![], vec![]));
1849 let compiled = compiler.compile(expr).unwrap();
1850 let expected_type_info =
1851 internal::rib_input_type_info(vec![("request", request_value_type)]);
1852
1853 assert_eq!(compiled.rib_input_type_info, expected_type_info);
1854 }
1855 }
1856
1857 mod internal {
1858 use crate::wit_type::*;
1859 use crate::wit_type::{case, str, u64, unit_case, variant};
1860 use crate::{ComponentDependency, ComponentDependencyKey, RibInputTypeInfo};
1861 use std::collections::HashMap;
1862 use uuid::Uuid;
1863
1864 pub(crate) fn metadata_with_variants() -> ComponentDependency {
1865 let instance = WitExport::Interface(WitInterface {
1866 name: "golem:it/api".to_string(),
1867 functions: vec![WitFunction {
1868 name: "foo".to_string(),
1869 parameters: vec![WitFunctionParameter {
1870 name: "param1".to_string(),
1871 typ: variant(vec![
1872 case("register-user", u64()),
1873 case("process-user", str()),
1874 unit_case("validate"),
1875 ]),
1876 }],
1877 result: Some(WitFunctionResult {
1878 typ: WitType::Handle(TypeHandle {
1879 resource_id: AnalysedResourceId(0),
1880 mode: AnalysedResourceMode::Owned,
1881 name: None,
1882 owner: None,
1883 }),
1884 }),
1885 }],
1886 });
1887
1888 let component_info = ComponentDependencyKey {
1889 component_name: "foo".to_string(),
1890 component_id: Uuid::new_v4(),
1891 component_revision: 0,
1892 root_package_name: None,
1893 root_package_version: None,
1894 };
1895
1896 ComponentDependency::from_wit_metadata(component_info, &[instance]).unwrap()
1897 }
1898
1899 pub(crate) fn get_component_metadata(
1900 function_name: &str,
1901 input_types: Vec<WitType>,
1902 output: WitType,
1903 ) -> ComponentDependency {
1904 let analysed_function_parameters = input_types
1905 .into_iter()
1906 .enumerate()
1907 .map(|(index, typ)| WitFunctionParameter {
1908 name: format!("param{index}"),
1909 typ,
1910 })
1911 .collect();
1912
1913 let component_info = ComponentDependencyKey {
1914 component_name: "foo".to_string(),
1915 component_id: Uuid::new_v4(),
1916 component_revision: 0,
1917 root_package_name: None,
1918 root_package_version: None,
1919 };
1920
1921 let exports = vec![WitExport::Function(WitFunction {
1922 name: function_name.to_string(),
1923 parameters: analysed_function_parameters,
1924 result: Some(WitFunctionResult { typ: output }),
1925 })];
1926 ComponentDependency::from_wit_metadata(component_info, &exports).unwrap()
1927 }
1928
1929 pub(crate) fn rib_input_type_info(types: Vec<(&str, WitType)>) -> RibInputTypeInfo {
1930 let mut type_info = HashMap::new();
1931 for (name, typ) in types {
1932 type_info.insert(name.to_string(), typ);
1933 }
1934 RibInputTypeInfo { types: type_info }
1935 }
1936 }
1937}