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