1use crate::code_bld::CodeBuilder;
6use crate::ctx::Context;
7use swamp_semantic::{BinaryOperatorKind, Expression, ExpressionKind};
8use swamp_types::TypeKind;
9use swamp_vm_layout::LayoutCache;
10use swamp_vm_types::types::{int_type, Destination, TypedRegister, VmType};
11use swamp_vm_types::MemoryLocation;
12
13impl CodeBuilder<'_> {
14 #[allow(clippy::too_many_lines)]
32 pub fn emit_expression(&mut self, output: &Destination, expr: &Expression, ctx: &Context) {
33 let node = &expr.node;
34
35 if self.options.should_show_debug {
36 self.debug_expression(expr, "emitting expression");
37 }
38
39 match &expr.kind {
42 ExpressionKind::InitializerList(_element_type, expressions) => {
43 self.emit_vec_like_collection_init_from_initialization_list(
44 output,
45 expressions,
46 &expr.node,
47 ctx,
48 );
49 return;
50 }
51 ExpressionKind::InitializerPairList(_element_type, expressions) => {
52 self.emit_map_like_init_from_initialization_pair_list(
53 output,
54 expressions,
55 &expr.node,
56 ctx,
57 );
58 return;
59 }
60 _ => {}
61 }
62
63 if !matches!(output, Destination::Memory(_))
66 && Self::rvalue_needs_memory_location_to_materialize_in(
67 &mut self.state.layout_cache,
68 expr,
69 )
70 {
71 let expr_basic_type = self.state.layout_cache.layout(&expr.ty);
72 let temp_materialization_target = self
73 .allocate_frame_space_and_return_destination_to_it(
74 &expr_basic_type,
75 &expr.node,
76 "rvalue temporary materialization",
77 );
78
79 self.emit_expression(&temp_materialization_target, expr, ctx);
80
81 self.builder.add_mov_reg(
82 output.grab_register(),
83 &temp_materialization_target
84 .grab_memory_location()
85 .base_ptr_reg,
86 node,
87 "copy temp materialization memory pointer reg",
88 );
89
90 return;
91 }
92
93 let hwm = self.temp_registers.save_mark();
94
95 match &expr.kind {
96 &ExpressionKind::InitializerList(_, _) | &ExpressionKind::InitializerPairList(_, _) => {
97 panic!("handled earlier")
98 }
99 ExpressionKind::Error(_) => {
100 return;
101 }
102
103 ExpressionKind::StringLiteral(str) => {
104 self.emit_string_literal(output, node, str, ctx);
105 }
106 ExpressionKind::IntLiteral(int) => match output {
107 Destination::Register(target_reg) => {
108 self.builder.add_mov_32_immediate_value(
109 target_reg,
110 *int as u32,
111 node,
112 "int literal",
113 );
114 }
115 Destination::Memory(location) => {
116 let temp_int_literal_reg = self.temp_registers.allocate(
117 VmType::new_contained_in_register(int_type()),
118 "temporary for int literal",
119 );
120 self.builder.add_mov_32_immediate_value(
121 temp_int_literal_reg.register(),
122 *int as u32,
123 node,
124 "int literal",
125 );
126 self.builder.add_st32_using_ptr_with_offset(
127 location,
128 temp_int_literal_reg.register(),
129 node,
130 &format!("copy int literal into destination memory {location} <- {temp_int_literal_reg}"),
131 );
132 }
133 Destination::Unit => {
134 panic!("int can not materialize into nothing")
135 }
136 },
137 ExpressionKind::ByteLiteral(byte) => match output {
138 Destination::Register(target_reg) => {
139 self.builder
140 .add_mov8_immediate(target_reg, *byte, node, "int literal");
141 }
142 Destination::Memory(location) => {
143 let temp_byte_literal_reg = self.temp_registers.allocate(
144 VmType::new_contained_in_register(int_type()),
145 "temporary for byte literal",
146 );
147 self.builder.add_mov8_immediate(
148 temp_byte_literal_reg.register(),
149 *byte,
150 node,
151 "byte literal",
152 );
153 self.builder.add_st8_using_ptr_with_offset(
154 location,
155 temp_byte_literal_reg.register(),
156 node,
157 &format!("copy byte literal into destination memory {location} <- {temp_byte_literal_reg}"),
158 );
159 }
160 Destination::Unit => {
161 panic!("byte can not materialize into nothing")
162 }
163 },
164 ExpressionKind::FloatLiteral(fixed_point) => match output {
165 Destination::Register(target_reg) => {
166 self.builder.add_mov_32_immediate_value(
167 target_reg,
168 fixed_point.inner() as u32,
169 node,
170 "float literal",
171 );
172 }
173 Destination::Memory(location) => {
174 let temp_fixed_point_temp_reg = self.temp_registers.allocate(
175 VmType::new_contained_in_register(int_type()),
176 "temporary for float literal",
177 );
178 self.builder.add_mov_32_immediate_value(
179 temp_fixed_point_temp_reg.register(),
180 fixed_point.inner() as u32,
181 node,
182 "float literal",
183 );
184 self.builder.add_st32_using_ptr_with_offset(
185 location,
186 temp_fixed_point_temp_reg.register(),
187 node,
188 "copy float literal into destination memory",
189 );
190 }
191 Destination::Unit => {
192 panic!("int can not materialize into nothing")
193 }
194 },
195 ExpressionKind::NoneLiteral => {
196 match output {
199 Destination::Register(target_reg) => {
200 self.builder
201 .add_mov8_immediate(target_reg, 0, node, "none literal");
202 }
203 Destination::Memory(location) => {
204 let temp_none_literal_reg = self.temp_registers.allocate(
205 VmType::new_contained_in_register(int_type()),
206 "temporary for none literal",
207 );
208 self.builder.add_mov8_immediate(
209 temp_none_literal_reg.register(),
210 0,
211 node,
212 "none literal",
213 );
214
215 self.builder.add_st8_using_ptr_with_offset(
216 location,
217 temp_none_literal_reg.register(),
218 node,
219 "copy none literal into destination memory",
220 );
221 }
222 Destination::Unit => {
223 panic!("none can not materialize into nothing")
224 }
225 }
226 }
227 ExpressionKind::BoolLiteral(truthy) => match output {
228 Destination::Register(target_reg) => {
229 self.builder.add_mov8_immediate(
230 target_reg,
231 u8::from(*truthy),
232 node,
233 "bool literal",
234 );
235 }
236 Destination::Memory(location) => {
237 let temp_bool_literal_reg = self.temp_registers.allocate(
238 VmType::new_contained_in_register(int_type()),
239 "temporary for bool literal",
240 );
241 self.builder.add_mov8_immediate(
242 temp_bool_literal_reg.register(),
243 u8::from(*truthy),
244 node,
245 "bool literal",
246 );
247
248 self.builder.add_st8_using_ptr_with_offset(
249 location,
250 temp_bool_literal_reg.register(),
251 node,
252 "copy bool literal into destination memory",
253 );
254 }
255 Destination::Unit => {
256 panic!("int can not materialize into nothing")
257 }
258 },
259
260 ExpressionKind::EnumVariantLiteral(enum_variant, expressions) => {
261 self.emit_enum_variant_to_memory_location(
263 &output.grab_aggregate_memory_location(),
264 &expr.ty,
265 enum_variant,
266 expressions,
267 node,
268 ctx,
269 );
270 }
271 ExpressionKind::TupleLiteral(expressions) => {
272 self.emit_tuple_literal_into_memory(
274 &output.grab_aggregate_memory_location(),
275 &expr.ty,
276 expressions,
277 ctx,
278 node,
279 );
280 }
281
282 ExpressionKind::If(condition, true_expression, maybe_false_expression) => {
283 self.emit_if(
284 output,
285 condition,
286 true_expression,
287 maybe_false_expression.as_deref(),
288 ctx,
289 );
290 }
291 ExpressionKind::Block(expressions) => {
292 self.emit_block(output, expressions, ctx);
293 }
294 ExpressionKind::NamedStructLiteral(inner) => {
295 self.emit_expression(output, inner, ctx);
296 }
297 ExpressionKind::AnonymousStructLiteral(anon_struct) => {
298 self.emit_anonymous_struct_literal_into_memory_location(
300 &output.grab_aggregate_memory_location(),
301 anon_struct,
302 &expr.ty,
303 node,
304 "struct literal",
305 ctx,
306 );
307 }
308 ExpressionKind::Option(maybe_option) => self
309 .emit_option_expression_into_target_memory_location(
310 output,
311 node,
312 maybe_option.as_deref(),
313 ctx,
314 ),
315 ExpressionKind::ConstantAccess(constant_ref) => {
316 self.emit_constant_access(output, constant_ref, &expr.node, ctx);
317 }
318 ExpressionKind::VariableAccess(variable_ref) => {
319 let variable_register = self.get_variable_register(variable_ref).clone();
320 let source_destination = Destination::Register(variable_register);
321 self.emit_copy_value_between_destinations(
322 output,
323 &source_destination,
324 node,
325 &format!(
326 "copy variable '{}' to destination",
327 variable_ref.assigned_name
328 ),
329 );
330 }
331 ExpressionKind::BorrowMutRef(expression) => {
332 self.emit_borrow_mutable_reference(
333 output.grab_register(),
334 &expr.node,
335 expression,
336 ctx,
337 ); }
339 ExpressionKind::BinaryOp(operator) => match operator.kind {
340 BinaryOperatorKind::NoneCoalesce => self.emit_none_coalesce_operator(
341 output,
342 &operator.left,
343 &operator.right,
344 &operator.node,
345 ctx,
346 ),
347 _ => match output {
348 Destination::Register(reg) => {
349 self.emit_binary_operator(reg, operator, ctx);
350 }
351 Destination::Memory(mem_loc) => {
352 let temp_reg = self
353 .temp_registers
354 .allocate(mem_loc.ty.clone(), "binary_op_temp");
355 self.emit_binary_operator(temp_reg.register(), operator, ctx);
356
357 self.builder.add_st32_using_ptr_with_offset(
358 mem_loc,
359 temp_reg.register(),
360 node,
361 "store binary op result directly to memory with offset",
362 );
363 }
364 Destination::Unit => {
365 panic!("binary operator always returns a value")
366 }
367 },
368 },
369 ExpressionKind::UnaryOp(operator) => match output {
370 Destination::Register(reg) => {
371 self.emit_unary_operator(reg, operator, ctx);
372 }
373 Destination::Memory(mem_loc) => {
374 let temp_reg = self
375 .temp_registers
376 .allocate(mem_loc.ty.clone(), "unary_op_temp");
377 self.emit_unary_operator(temp_reg.register(), operator, ctx);
378
379 self.builder.add_st32_using_ptr_with_offset(
380 mem_loc,
381 temp_reg.register(),
382 node,
383 "store unary op result directly to memory with offset",
384 );
385 }
386 Destination::Unit => {
387 panic!("unary operator always returns a value")
388 }
389 },
390 ExpressionKind::PostfixChain(start, chain) => {
391 self.emit_postfix_chain(output, start, chain, ctx);
392 }
393 ExpressionKind::Match(match_expr) => match &*match_expr.expression.ty.kind {
394 TypeKind::Enum(_enum_type) => {
395 self.emit_match_enum(output, match_expr, ctx);
396 }
397 _ => {
398 self.emit_match_literal(output, match_expr, ctx);
399 }
400 },
401 ExpressionKind::Guard(guards) => self.emit_guard(output, guards, ctx),
402 ExpressionKind::When(bindings, true_expr, false_expr) => {
403 self.emit_when(output, bindings, true_expr, false_expr.as_deref(), ctx);
404 }
405 ExpressionKind::IntrinsicCallEx(intrinsic_fn, arguments) => {
406 self.emit_single_intrinsic_call(output, &expr.node, intrinsic_fn, arguments, ctx);
407 }
408 ExpressionKind::CoerceToAny(a) => {
409 self.emit_coerce_to_any(output, a, ctx);
410 }
411 ExpressionKind::CoerceOptionToBool(a) => {
412 self.emit_coerce_option_to_bool(output.grab_register(), a, ctx);
413 }
414 ExpressionKind::CoerceIntToChar(a) => {
415 self.emit_coerce_int_to_char(output.grab_register(), a, ctx);
416 }
417 ExpressionKind::CoerceIntToByte(a) => {
418 self.emit_coerce_int_to_byte(output, a, ctx);
419 }
420 ExpressionKind::InternalCall(internal, arguments) => {
421 self.emit_internal_call(output, &expr.node, internal, arguments, ctx);
422 }
423 ExpressionKind::HostCall(host_fn, arguments) => {
424 self.emit_host_call(output, &expr.node, host_fn, arguments, ctx);
425 }
426
427 ExpressionKind::TupleDestructuring(variables, tuple_type, tuple_expression) => {
429 debug_assert!(output.is_unit());
430 self.emit_tuple_destructuring(variables, tuple_type, tuple_expression, ctx);
431 }
432 ExpressionKind::Assignment(target_mut_location_expr, source_expr) => {
433 debug_assert!(output.is_unit());
434 self.emit_assignment(target_mut_location_expr, source_expr, "", ctx);
435 }
436 ExpressionKind::VariableDefinition(variable, expression) => {
437 debug_assert!(output.is_unit());
438 self.emit_variable_definition(variable, expression, ctx);
439 }
440 ExpressionKind::VariableDefinitionLValue(variable, location_expr) => {
441 match output {
444 Destination::Unit => {
445 let lvalue_destination = self.emit_lvalue_address(location_expr, ctx);
446
447 let alias_register = self.get_variable_register(variable).clone();
448
449 self.emit_compute_effective_address_to_target_register(
450 &alias_register,
451 &lvalue_destination,
452 &variable.name,
453 "initialize alias variable with lvalue address",
454 );
455 }
456 _ => {
457 panic!("VariableDefinitionLValue should only be used with Unit destination")
458 }
459 }
460 }
461 ExpressionKind::VariableReassignment(variable, expression) => {
462 assert!(output.is_unit());
463 self.emit_variable_reassignment(variable, expression, ctx);
464 }
465 ExpressionKind::CompoundAssignment(target_location, operator_kind, source_expr) => {
466 assert!(output.is_unit());
467 self.emit_compound_assignment(target_location, operator_kind, source_expr, ctx);
468 }
469 ExpressionKind::ForLoop(for_pattern, collection, lambda_expr) => {
470 if !output.is_unit() {
471 let x = 3;
472 eprintln!("problem");
473 }
474 assert!(output.is_unit());
475 self.emit_for_loop(
476 output,
477 &expr.node,
478 for_pattern,
479 collection,
480 lambda_expr,
481 ctx,
482 );
483 }
484 ExpressionKind::WhileLoop(condition, expression) => {
485 assert!(output.is_unit());
486 self.emit_while_loop(condition, expression, ctx);
487 }
488
489 ExpressionKind::Lambda(_vec, _x) => {
491 panic!("something went wrong. non-capturing lambdas can not be evaluated")
492 }
493 }
494
495 self.temp_registers.restore_to_mark(hwm);
496 }
497
498 pub(crate) fn rvalue_needs_memory_location_to_materialize_in(
499 layout_cache: &mut LayoutCache,
500 expr: &Expression,
501 ) -> bool {
502 let specific_kind_of_expression_needs_memory_target = match &expr.kind {
503 ExpressionKind::EnumVariantLiteral(_, _)
505 | ExpressionKind::TupleLiteral(_)
506 | ExpressionKind::InitializerList(_, _)
507 | ExpressionKind::InitializerPairList(_, _) => true,
508 ExpressionKind::Option(_)
509 | ExpressionKind::AnonymousStructLiteral(_)
510 | ExpressionKind::CoerceToAny(_) => true,
511 _ => false,
512 };
513
514 if specific_kind_of_expression_needs_memory_target {
515 true
516 } else {
517 match &expr.kind {
519 ExpressionKind::InternalCall(_, _)
520 | ExpressionKind::HostCall(_, _)
521 | ExpressionKind::IntrinsicCallEx(_, _) => {
522 let basic_type = layout_cache.layout(&expr.ty);
523 basic_type.is_aggregate()
524 }
525 _ => false,
526 }
527 }
528 }
529
530 pub(crate) fn emit_expression_into_target_memory(
531 &mut self,
532 memory_location: &MemoryLocation,
533 expr: &Expression,
534 comment: &str,
535 ctx: &Context,
536 ) {
537 if matches!(
539 expr.kind,
540 ExpressionKind::InitializerList(_, _) | ExpressionKind::InitializerPairList(_, _)
541 ) {
542 self.emit_initialize_memory_for_any_type(
543 memory_location,
544 &expr.node,
545 &format!("{comment} - initialize memory for collection"),
546 );
547 }
548
549 let output = Destination::new_location(memory_location.clone());
550 self.emit_expression(&output, expr, ctx);
551 }
552
553 pub(crate) fn emit_expression_into_register(
554 &mut self,
555 target_register: &TypedRegister,
556 expr: &Expression,
557 comment: &str,
558 ctx: &Context,
559 ) {
560 let output = Destination::new_reg(target_register.clone());
561
562 self.emit_expression(&output, expr, ctx);
563 }
564}