1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use crate::transformer::{Collection, Transformer};
8use source_map_node::Node;
9use swamp_semantic::{BooleanExpression, Expression, ForPattern, Iterable};
10use swamp_types::TypeKind;
11use swamp_types::TypeRef;
12use swamp_vm_types::types::{Place, TypedRegister};
13
14impl CodeBuilder<'_> {
15 pub fn emit_statement(&mut self, expr: &Expression, ctx: &Context) {
16 debug_assert!(matches!(&*expr.ty.kind, TypeKind::Unit | TypeKind::Never));
17 let output_destination = Place::new_unit();
18 self.emit_expression(&output_destination, expr, ctx);
19 }
20
21 pub(crate) fn emit_for_loop(
22 &mut self,
23 destination: &Place,
24 node: &Node,
25 for_pattern: &ForPattern,
26 iterable: &Iterable,
27 lambda_non_capturing_expr: &Expression,
28 ctx: &Context,
29 ) {
30 let collection_type = &iterable.resolved_expression.ty;
37 let hwm = self.temp_registers.save_mark();
38
39 let variables_are_mutable = match for_pattern {
42 ForPattern::Single(var) => var.is_mutable(),
43 ForPattern::Pair(var1, var2) => var1.is_mutable() || var2.is_mutable(),
44 };
45 let allow_temporary = !variables_are_mutable;
46
47 let collection_ptr_reg = self.emit_scalar_rvalue_or_pointer_to_temporary(
48 &iterable.resolved_expression,
49 ctx,
50 allow_temporary,
51 );
52 let underlying_collection = collection_type;
53 match &*underlying_collection.kind {
54 TypeKind::StackStorage(_element_type, _)
55 | TypeKind::StackView(_element_type)
56 | TypeKind::QueueStorage(_element_type, _)
57 | TypeKind::QueueView(_element_type)
58 | TypeKind::DynamicLengthVecView(_element_type)
59 | TypeKind::VecStorage(_element_type, ..)
60 | TypeKind::FixedCapacityAndLengthArray(_element_type, _)
61 | TypeKind::SliceView(_element_type) => {
62 self.emit_for_loop_lambda(
63 destination,
64 node,
65 Collection::Vec,
66 &collection_ptr_reg,
67 collection_type,
68 for_pattern,
69 lambda_non_capturing_expr,
70 ctx,
71 );
72 }
73 TypeKind::SparseStorage(element_type, _) | TypeKind::SparseView(element_type) => {
74 self.emit_for_loop_lambda(
75 destination,
76 node,
77 Collection::Sparse,
78 &collection_ptr_reg,
79 collection_type,
80 for_pattern,
81 lambda_non_capturing_expr,
82 ctx,
83 );
84 }
85 TypeKind::DynamicLengthMapView(_key, _value)
86 | TypeKind::MapStorage(_key, _value, ..) => {
87 self.emit_for_loop_lambda(
88 destination,
89 node,
90 Collection::Map,
91 &collection_ptr_reg,
92 collection_type,
93 for_pattern,
94 lambda_non_capturing_expr,
95 ctx,
96 );
97 }
98 TypeKind::StringView(..) | TypeKind::StringStorage(..) => {
99 self.emit_for_loop_lambda(
100 destination,
101 node,
102 Collection::String,
103 &collection_ptr_reg,
104 collection_type,
105 for_pattern,
106 lambda_non_capturing_expr,
107 ctx,
108 );
109 }
110
111 _ => {
112 panic!("can not iterate this collection {underlying_collection}");
113 }
114 }
115
116 self.temp_registers.restore_to_mark(hwm);
117 }
118
119 fn emit_for_loop_lambda(
120 &mut self,
121 target_reg: &Place,
122 node: &Node,
123 collection: Collection,
124 source_collection: &TypedRegister,
125 source_collection_type: &TypeRef,
126 for_pattern: &ForPattern,
127 lambda_expr: &Expression,
128 ctx: &Context,
129 ) {
130 let variables = match for_pattern {
131 ForPattern::Single(a) => vec![a.clone()],
132 ForPattern::Pair(a, b) => vec![a.clone(), b.clone()],
133 };
134
135 self.emit_iterate_over_collection_with_lambda(
136 target_reg,
137 node,
138 collection,
139 Transformer::For,
140 source_collection,
141 (variables, lambda_expr),
142 ctx,
143 );
144 }
145
146 pub(crate) fn emit_while_loop(
147 &mut self,
148 condition: &BooleanExpression,
149 expression: &Expression,
150 ctx: &Context,
151 ) {
152 let ip_for_condition = self.builder.position();
156
157 let jump_on_false_condition = self.emit_condition_context(condition, ctx);
158
159 self.emit_statement(expression, ctx);
161
162 self.builder
164 .add_jmp(ip_for_condition, &expression.node, "jmp to while condition");
165
166 self.builder.patch_jump_here(jump_on_false_condition);
167 }
168}