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