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::{Destination, 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 = Destination::new_unit();
18 self.emit_expression(&output_destination, expr, ctx);
19 }
20
21 pub(crate) fn emit_for_loop(
22 &mut self,
23 destination: &Destination,
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::Range(_range_struct_ref) => {
55 self.emit_for_loop_lambda(
56 destination,
57 node,
58 Collection::Range,
59 &collection_ptr_reg,
60 collection_type,
61 for_pattern,
62 lambda_non_capturing_expr,
63 ctx,
64 );
65 }
66
67 TypeKind::StackStorage(_element_type, _)
68 | TypeKind::StackView(_element_type)
69 | TypeKind::QueueStorage(_element_type, _)
70 | TypeKind::QueueView(_element_type)
71 | TypeKind::DynamicLengthVecView(_element_type)
72 | TypeKind::VecStorage(_element_type, ..)
73 | TypeKind::FixedCapacityAndLengthArray(_element_type, _)
74 | TypeKind::SliceView(_element_type) => {
75 self.emit_for_loop_lambda(
76 destination,
77 node,
78 Collection::Vec,
79 &collection_ptr_reg,
80 collection_type,
81 for_pattern,
82 lambda_non_capturing_expr,
83 ctx,
84 );
85 }
86 TypeKind::SparseStorage(element_type, _) | TypeKind::SparseView(element_type) => {
87 self.emit_for_loop_lambda(
88 destination,
89 node,
90 Collection::Sparse,
91 &collection_ptr_reg,
92 collection_type,
93 for_pattern,
94 lambda_non_capturing_expr,
95 ctx,
96 );
97 }
98 TypeKind::DynamicLengthMapView(_key, _value) | TypeKind::MapStorage(_key, _value, ..) => {
99 self.emit_for_loop_lambda(
100 destination,
101 node,
102 Collection::Map,
103 &collection_ptr_reg,
104 collection_type,
105 for_pattern,
106 lambda_non_capturing_expr,
107 ctx,
108 );
109 }
110 TypeKind::String(..) => {
111 self.emit_for_loop_lambda(
112 destination,
113 node,
114 Collection::String,
115 &collection_ptr_reg,
116 collection_type,
117 for_pattern,
118 lambda_non_capturing_expr,
119 ctx,
120 );
121 }
122
123 _ => {
124 panic!("can not iterate this collection {underlying_collection}");
125 }
126 }
127
128 self.temp_registers.restore_to_mark(hwm);
129 }
130
131 fn emit_for_loop_lambda(
132 &mut self,
133 target_reg: &Destination,
134 node: &Node,
135 collection: Collection,
136 source_collection: &TypedRegister,
137 source_collection_type: &TypeRef,
138 for_pattern: &ForPattern,
139 lambda_expr: &Expression,
140 ctx: &Context,
141 ) {
142 let variables = match for_pattern {
143 ForPattern::Single(a) => vec![a.clone()],
144 ForPattern::Pair(a, b) => vec![a.clone(), b.clone()],
145 };
146
147 self.emit_iterate_over_collection_with_lambda(
148 target_reg,
149 node,
150 collection,
151 Transformer::For,
152 source_collection,
153 (variables, lambda_expr),
154 ctx,
155 );
156 }
157
158 pub(crate) fn emit_while_loop(
159 &mut self,
160 condition: &BooleanExpression,
161 expression: &Expression,
162 ctx: &Context,
163 ) {
164 let ip_for_condition = self.builder.position();
168
169 let jump_on_false_condition = self.emit_condition_context(condition, ctx);
170
171 self.emit_statement(expression, ctx);
173
174 self.builder
176 .add_jmp(ip_for_condition, &expression.node, "jmp to while condition");
177
178 self.builder.patch_jump_here(jump_on_false_condition);
179 }
180}