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::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)
99 | TypeKind::MapStorage(_key, _value, ..) => {
100 self.emit_for_loop_lambda(
101 destination,
102 node,
103 Collection::Map,
104 &collection_ptr_reg,
105 collection_type,
106 for_pattern,
107 lambda_non_capturing_expr,
108 ctx,
109 );
110 }
111 TypeKind::StringView(..) | TypeKind::StringStorage(..) => {
112 self.emit_for_loop_lambda(
113 destination,
114 node,
115 Collection::String,
116 &collection_ptr_reg,
117 collection_type,
118 for_pattern,
119 lambda_non_capturing_expr,
120 ctx,
121 );
122 }
123
124 _ => {
125 panic!("can not iterate this collection {underlying_collection}");
126 }
127 }
128
129 self.temp_registers.restore_to_mark(hwm);
130 }
131
132 fn emit_for_loop_lambda(
133 &mut self,
134 target_reg: &Place,
135 node: &Node,
136 collection: Collection,
137 source_collection: &TypedRegister,
138 source_collection_type: &TypeRef,
139 for_pattern: &ForPattern,
140 lambda_expr: &Expression,
141 ctx: &Context,
142 ) {
143 let variables = match for_pattern {
144 ForPattern::Single(a) => vec![a.clone()],
145 ForPattern::Pair(a, b) => vec![a.clone(), b.clone()],
146 };
147
148 self.emit_iterate_over_collection_with_lambda(
149 target_reg,
150 node,
151 collection,
152 Transformer::For,
153 source_collection,
154 (variables, lambda_expr),
155 ctx,
156 );
157 }
158
159 pub(crate) fn emit_while_loop(
160 &mut self,
161 condition: &BooleanExpression,
162 expression: &Expression,
163 ctx: &Context,
164 ) {
165 let ip_for_condition = self.builder.position();
169
170 let jump_on_false_condition = self.emit_condition_context(condition, ctx);
171
172 self.emit_statement(expression, ctx);
174
175 self.builder
177 .add_jmp(ip_for_condition, &expression.node, "jmp to while condition");
178
179 self.builder.patch_jump_here(jump_on_false_condition);
180 }
181}