1pub mod alloc;
2pub mod alloc_util;
3pub mod constants;
4pub mod ctx;
5mod vec;
6
7use crate::alloc::{FrameMemoryRegion, ScopeAllocator};
8use crate::alloc_util::{
9 layout_struct, layout_tuple, layout_union, reserve_space_for_type, type_size_and_alignment,
10};
11use crate::ctx::Context;
12use crate::vec::{VECTOR_DATA_PTR_OFFSET, VECTOR_LENGTH_OFFSET};
13use seq_map::SeqMap;
14use std::ops::Deref;
15use swamp_script_semantic::{
16 ArgumentExpressionOrLocation, BinaryOperator, BinaryOperatorKind, BooleanExpression,
17 CompoundOperatorKind, EnumLiteralData, Expression, ExpressionKind, ForPattern, Function,
18 FunctionScopeState, InternalFunctionDefinition, InternalFunctionDefinitionRef,
19 InternalFunctionId, InternalMainExpression, Iterable, Literal, LocationAccessKind,
20 MutOrImmutableExpression, Postfix, PostfixKind, SingleLocationExpression,
21 SingleMutLocationExpression, StructInstantiation, VariableRef,
22};
23use swamp_script_types::{AnonymousStructType, EnumVariantType, Signature, StructTypeField, Type};
24
25use crate::constants::ConstantsManager;
26use swamp_script_semantic::intr::IntrinsicFunction;
27use swamp_vm_instr_build::{InstructionBuilder, PTR_SIZE, PatchPosition};
28use swamp_vm_types::{
29 BinaryInstruction, FrameMemoryAddress, FrameMemorySize, InstructionPosition, MemoryAddress,
30 MemoryAlignment, MemoryOffset, MemorySize,
31};
32use tracing::{info, trace};
33
34pub struct FunctionInfo {
35 pub starts_at_ip: InstructionPosition,
36 pub internal_function_definition: InternalFunctionDefinitionRef,
37}
38
39pub struct FunctionFixup {
40 pub patch_position: PatchPosition,
41 pub fn_id: InternalFunctionId,
42 }
44
45pub struct CodeGenState {
46 builder: InstructionBuilder,
47 constants: ConstantsManager,
48 function_infos: SeqMap<InternalFunctionId, FunctionInfo>,
49 function_fixups: Vec<FunctionFixup>,
50}
51
52impl CodeGenState {
53 pub fn create_function_sections(&self) -> SeqMap<InstructionPosition, String> {
54 let mut lookups = SeqMap::new();
55 for (_func_id, function_info) in &self.function_infos {
56 let description = format!(
57 "{}",
58 function_info.internal_function_definition.assigned_name
59 );
60 lookups
61 .insert(function_info.starts_at_ip.clone(), description)
62 .unwrap()
63 }
64
65 lookups
66 }
67}
68
69impl CodeGenState {
70 pub(crate) fn add_call(&mut self, internal_fn: &InternalFunctionDefinitionRef, comment: &str) {
71 let call_comment = &format!("calling {} ({})", internal_fn.assigned_name, comment);
72
73 if let Some(found) = self.function_infos.get(&internal_fn.program_unique_id) {
74 self.builder.add_call(&found.starts_at_ip, call_comment);
75 } else {
76 let patch_position = self.builder.add_call_placeholder(call_comment);
77 self.function_fixups.push(FunctionFixup {
78 patch_position,
79 fn_id: internal_fn.program_unique_id,
80 });
81 }
82 }
83}
84
85impl CodeGenState {
86 #[must_use]
87 pub fn instructions(&self) -> &[BinaryInstruction] {
88 &self.builder.instructions
89 }
90
91 #[must_use]
92 pub fn comments(&self) -> &[String] {
93 &self.builder.comments
94 }
95
96 pub fn finalize(&mut self) {
97 for function_fixup in &self.function_fixups {
98 let func = self.function_infos.get(&function_fixup.fn_id).unwrap();
99 self.builder.patch_call(
100 PatchPosition(InstructionPosition(function_fixup.patch_position.0.0)),
101 &func.starts_at_ip,
102 );
103 }
104 }
105}
106
107pub struct GenOptions {
108 pub is_halt_function: bool,
109}
110impl Default for CodeGenState {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116impl CodeGenState {
117 #[must_use]
118 pub fn new() -> Self {
119 Self {
120 builder: InstructionBuilder::default(),
121 constants: ConstantsManager::new(),
122 function_infos: SeqMap::default(),
123 function_fixups: vec![],
124 }
125 }
126
127 #[must_use]
128 pub fn take_instructions_and_constants(self) -> (Vec<BinaryInstruction>, Vec<u8>) {
129 (self.builder.instructions, self.constants.take_data())
130 }
131
132 pub fn gen_function_def(
133 &mut self,
134 internal_fn_def: &InternalFunctionDefinitionRef,
135 options: &GenOptions,
136 ) {
137 assert_ne!(internal_fn_def.program_unique_id, 0);
139 self.function_infos
140 .insert(
141 internal_fn_def.program_unique_id,
142 FunctionInfo {
143 starts_at_ip: self.builder.position(),
144 internal_function_definition: internal_fn_def.clone(),
145 },
146 )
147 .unwrap();
148
149 let mut function_generator = FunctionCodeGen::new(self, internal_fn_def.program_unique_id);
150
151 let mut ctx = Context::new(FrameMemoryRegion::new(
152 FrameMemoryAddress(0),
153 MemorySize(512),
154 ));
155
156 function_generator.layout_variables(
157 &internal_fn_def.function_scope_state,
158 &internal_fn_def.signature.return_type,
159 );
160
161 function_generator.gen_expression(&internal_fn_def.body, &mut ctx);
162
163 self.finalize_function(options);
164 }
165
166 pub fn finalize_function(&mut self, options: &GenOptions) {
167 if options.is_halt_function {
168 self.builder.add_hlt("");
169 } else {
170 self.builder.add_ret("");
171 }
172 }
173
174 pub fn gen_main_function(&mut self, main: &InternalMainExpression, options: &GenOptions) {
175 let mut function_generator = FunctionCodeGen::new(self, main.program_unique_id);
176
177 function_generator.layout_variables(&main.function_scope_state, &main.expression.ty);
178 let mut empty_ctx = Context::new(FrameMemoryRegion::default()); function_generator.gen_expression(&main.expression, &mut empty_ctx);
180 self.finalize_function(options);
181 }
182}
183
184pub struct FunctionCodeGen<'a> {
185 state: &'a mut CodeGenState,
186 variable_offsets: SeqMap<usize, FrameMemoryRegion>,
187 frame_size: FrameMemorySize,
188 extra_frame_allocator: ScopeAllocator,
189 temp_allocator: ScopeAllocator,
190 fn_id: InternalFunctionId,
191}
192
193impl<'a> FunctionCodeGen<'a> {
194 #[must_use]
195 pub fn new(state: &'a mut CodeGenState, fn_id: InternalFunctionId) -> Self {
196 Self {
197 fn_id,
198 state,
199 variable_offsets: SeqMap::default(),
200 frame_size: FrameMemorySize(0),
201 extra_frame_allocator: ScopeAllocator::new(FrameMemoryRegion::default()),
202 temp_allocator: ScopeAllocator::new(FrameMemoryRegion::default()),
203 }
204 }
205
206 pub fn reserve(ty: &Type, allocator: &mut ScopeAllocator) -> FrameMemoryRegion {
207 let (size, alignment) = type_size_and_alignment(ty);
208 allocator.reserve(size, alignment)
209 }
210
211 pub fn layout_variables(&mut self, variables: &Vec<VariableRef>, return_type: &Type) {
212 let mut allocator = ScopeAllocator::new(FrameMemoryRegion::new(
213 FrameMemoryAddress(0),
214 MemorySize(1024),
215 ));
216 let _current_offset = Self::reserve(return_type, &mut allocator);
217
218 let mut enter_comment = "variables:\n".to_string();
219
220 for var_ref in variables {
221 let var_target = Self::reserve(&var_ref.resolved_type, &mut allocator);
222 trace!(?var_ref.assigned_name, ?var_target, "laying out");
223 enter_comment += &format!(
224 " ${:04X}:{} {}\n",
225 var_target.addr.0, var_target.size.0, var_ref.assigned_name
226 );
227 self.variable_offsets
228 .insert(var_ref.unique_id_within_function, var_target)
229 .unwrap();
230 }
231
232 let extra_frame_size = MemorySize(80);
233 let extra_target = FrameMemoryRegion::new(allocator.addr(), extra_frame_size);
234 self.extra_frame_allocator = ScopeAllocator::new(extra_target);
235 self.frame_size = allocator.addr().as_size().add(extra_frame_size);
236
237 self.state
238 .builder
239 .add_enter(self.frame_size, &enter_comment);
240
241 self.temp_allocator = ScopeAllocator::new(FrameMemoryRegion::new(
242 FrameMemoryAddress(self.frame_size.0),
243 MemorySize(1024),
244 ));
245 }
246
247 pub fn temp_memory_region_for_type(&mut self, ty: &Type, comment: &str) -> FrameMemoryRegion {
248 let new_target_info = reserve_space_for_type(ty, &mut self.temp_allocator);
249 trace!(?new_target_info, "creating temporary space");
250 new_target_info
251 }
252 pub fn temp_space_for_type(&mut self, ty: &Type, comment: &str) -> Context {
253 Context::new(self.temp_memory_region_for_type(ty, comment))
254 }
255
256 #[allow(clippy::single_match_else)]
259 pub fn gen_expression_for_access(
260 &mut self,
261 expr: &Expression,
262 ctx: &Context,
263 ) -> FrameMemoryRegion {
264 match &expr.kind {
265 ExpressionKind::VariableAccess(var_ref) => {
266 let frame_address = self
267 .variable_offsets
268 .get(&var_ref.unique_id_within_function)
269 .unwrap();
270
271 *frame_address
272 }
273
274 _ => {
275 let mut temp_ctx = self.temp_space_for_type(&expr.ty, "expression");
276
277 self.gen_expression(expr, &mut temp_ctx);
278
279 temp_ctx.target()
280 }
281 }
282 }
283
284 pub(crate) fn extra_frame_space_for_type(&mut self, ty: &Type) -> Context {
285 let target = Self::reserve(ty, &mut self.extra_frame_allocator);
286 Context::new(target)
287 }
288
289 pub fn gen_expression(&mut self, expr: &Expression, ctx: &Context) {
290 match &expr.kind {
291 ExpressionKind::ConstantAccess(_) => todo!(),
292 ExpressionKind::VariableAccess(variable_ref) => {
293 self.gen_variable_access(variable_ref, ctx);
294 }
295 ExpressionKind::IntrinsicFunctionAccess(_) => todo!(),
296 ExpressionKind::InternalFunctionAccess(function) => {
297 self.internal_function_access(function, ctx);
298 }
299 ExpressionKind::ExternalFunctionAccess(_) => todo!(),
300 ExpressionKind::BinaryOp(operator) => self.gen_binary_operator(operator, ctx),
301 ExpressionKind::UnaryOp(_) => todo!(),
302 ExpressionKind::PostfixChain(start, chain) => self.gen_postfix_chain(start, chain, ctx),
303 ExpressionKind::CoerceOptionToBool(_) => todo!(),
304 ExpressionKind::FunctionCall(_, _, _) => todo!(),
305 ExpressionKind::InterpolatedString(_) => todo!(),
306 ExpressionKind::VariableDefinition(variable, expression) => {
307 self.gen_variable_definition(variable, expression, ctx);
308 }
309 ExpressionKind::VariableReassignment(variable, expression) => {
310 self.gen_variable_reassignment(variable, expression, ctx);
311 }
312 ExpressionKind::StructInstantiation(struct_literal) => {
313 self.gen_struct_literal(struct_literal, ctx)
314 }
315 ExpressionKind::AnonymousStructLiteral(_) => todo!(),
316 ExpressionKind::Literal(basic_literal) => self.gen_literal(basic_literal, ctx),
317 ExpressionKind::Option(maybe_option) => {
318 self.gen_option_expression(maybe_option.as_deref(), ctx)
319 }
320 ExpressionKind::Range(_, _, _) => todo!(),
321 ExpressionKind::ForLoop(a, b, c) => self.gen_for_loop(a, b, c, ctx),
322 ExpressionKind::WhileLoop(condition, expression) => {
323 self.gen_while_loop(condition, expression, ctx);
324 }
325 ExpressionKind::Block(expressions) => self.gen_block(expressions, ctx),
326 ExpressionKind::Match(_) => todo!(),
327 ExpressionKind::Guard(_) => todo!(),
328 ExpressionKind::If(conditional, true_expr, false_expr) => {
329 self.gen_if(conditional, true_expr, false_expr.as_deref(), ctx);
330 }
331 ExpressionKind::When(_, _, _) => todo!(),
332 ExpressionKind::TupleDestructuring(_, _, _) => todo!(),
333 ExpressionKind::Assignment(_, _) => todo!(),
334 ExpressionKind::CompoundAssignment(target_location, operator_kind, source_expr) => {
335 self.compound_assignment(target_location, operator_kind, source_expr, ctx);
336 }
337 ExpressionKind::IntrinsicCallMut(_, _, _) => todo!(),
338 ExpressionKind::IntrinsicCallEx(intrinsic_fn, arguments) => {
339 self.gen_intrinsic_call_ex(intrinsic_fn, arguments, ctx);
340 }
341 }
342 }
343
344 fn gen_binary_operator(&mut self, binary_operator: &BinaryOperator, ctx: &Context) {
345 match (&binary_operator.left.ty, &binary_operator.right.ty) {
346 (Type::Int, Type::Int) => self.gen_binary_operator_i32(binary_operator, ctx),
347 _ => todo!(),
348 }
349 }
350
351 fn gen_binary_operator_i32(&mut self, binary_operator: &BinaryOperator, ctx: &Context) {
352 let left_source = self.gen_expression_for_access(&binary_operator.left, ctx);
353 let right_source = self.gen_expression_for_access(&binary_operator.right, ctx);
354
355 match binary_operator.kind {
356 BinaryOperatorKind::Add => {
357 self.state.builder.add_add_i32(
358 ctx.addr(),
359 left_source.addr(),
360 right_source.addr(),
361 "i32 add",
362 );
363 }
364
365 BinaryOperatorKind::Subtract => todo!(),
366 BinaryOperatorKind::Multiply => todo!(),
367 BinaryOperatorKind::Divide => todo!(),
368 BinaryOperatorKind::Modulo => todo!(),
369 BinaryOperatorKind::LogicalOr => todo!(),
370 BinaryOperatorKind::LogicalAnd => todo!(),
371 BinaryOperatorKind::Equal => todo!(),
372 BinaryOperatorKind::NotEqual => todo!(),
373 BinaryOperatorKind::LessThan => {
374 self.state.builder.add_lt_i32(
375 ctx.addr(),
376 left_source.addr(),
377 right_source.addr(),
378 "i32 lt",
379 );
380 }
381 BinaryOperatorKind::LessEqual => todo!(),
382 BinaryOperatorKind::GreaterThan => todo!(),
383 BinaryOperatorKind::GreaterEqual => todo!(),
384 BinaryOperatorKind::RangeExclusive => todo!(),
385 }
386 }
387
388 fn gen_condition_context(
389 &mut self,
390 condition: &BooleanExpression,
391 ctx: &Context,
392 ) -> (Context, PatchPosition) {
393 let mut condition_ctx = self.extra_frame_space_for_type(&Type::Bool);
394 self.gen_expression(&condition.expression, &mut condition_ctx);
395
396 let jump_on_false_condition = self
397 .state
398 .builder
399 .add_conditional_jump_placeholder(condition_ctx.addr(), "jump boolean condition false");
400
401 (condition_ctx, jump_on_false_condition)
402 }
403
404 fn gen_if(
405 &mut self,
406 condition: &BooleanExpression,
407 true_expr: &Expression,
408 maybe_false_expr: Option<&Expression>,
409 ctx: &Context,
410 ) {
411 let (_condition_ctx, jump_on_false_condition) = self.gen_condition_context(condition, ctx);
412
413 self.gen_expression(true_expr, ctx);
415
416 if let Some(false_expr) = maybe_false_expr {
417 let skip_false_if_true = self
419 .state
420 .builder
421 .add_jump_placeholder("condition is false skip");
422
423 self.state.builder.patch_jump_here(jump_on_false_condition);
425
426 self.gen_expression(false_expr, ctx);
428
429 self.state.builder.patch_jump_here(skip_false_if_true);
430 } else {
431 self.state.builder.patch_jump_here(jump_on_false_condition);
432 }
433 }
434
435 fn gen_while_loop(
436 &mut self,
437 condition: &BooleanExpression,
438 expression: &Expression,
439 ctx: &Context,
440 ) {
441 assert_eq!(ctx.target_size().0, 0);
443
444 let ip_for_condition = self.state.builder.position();
445
446 let (_condition_ctx, jump_on_false_condition) = self.gen_condition_context(condition, ctx);
447
448 let mut unit_ctx = self.temp_space_for_type(&Type::Unit, "while body expression");
450 self.gen_expression(expression, &mut unit_ctx);
451
452 self.state
454 .builder
455 .add_jmp(ip_for_condition, "jmp to while condition");
456
457 self.state.builder.patch_jump_here(jump_on_false_condition);
458 }
459
460 fn gen_location_argument(
461 &mut self,
462 argument: &SingleLocationExpression,
463 ctx: &Context,
464 comment: &str,
465 ) {
466 let region = self.gen_lvalue_address(argument);
467
468 self.state
469 .builder
470 .add_mov(ctx.addr(), region.addr, region.size, comment)
471 }
472
473 fn gen_argument(
474 &mut self,
475 argument: &ArgumentExpressionOrLocation,
476 ctx: &Context,
477 comment: &str,
478 ) {
479 match &argument {
480 ArgumentExpressionOrLocation::Expression(found_expression) => {
481 self.gen_expression(found_expression, ctx);
482 }
483 ArgumentExpressionOrLocation::Location(location_expression) => {
484 self.gen_location_argument(location_expression, ctx, comment);
485 }
486 }
487 }
488
489 fn gen_mut_or_immute(
490 &mut self,
491 mut_or_immutable_expression: &MutOrImmutableExpression,
492 ctx: &mut Context,
493 ) {
494 match &mut_or_immutable_expression.expression_or_location {
495 ArgumentExpressionOrLocation::Expression(found_expression) => {
496 self.gen_expression(found_expression, ctx);
497 }
498 ArgumentExpressionOrLocation::Location(location_expression) => {
499 self.gen_lvalue_address(location_expression);
500 }
501 }
502 }
503 fn gen_variable_assignment(
504 &mut self,
505 variable: &VariableRef,
506 mut_or_immutable_expression: &MutOrImmutableExpression,
507 ctx: &Context,
508 ) {
509 let target_relative_frame_pointer = self
510 .variable_offsets
511 .get(&variable.unique_id_within_function)
512 .unwrap_or_else(|| panic!("{}", variable.assigned_name));
513
514 let mut init_ctx =
515 ctx.with_target(*target_relative_frame_pointer, "variable assignment target");
516
517 self.gen_mut_or_immute(mut_or_immutable_expression, &mut init_ctx);
518 }
519
520 fn gen_variable_definition(
521 &mut self,
522 variable: &VariableRef,
523 mut_or_immutable_expression: &MutOrImmutableExpression,
524 ctx: &Context,
525 ) {
526 self.gen_variable_assignment(variable, mut_or_immutable_expression, ctx);
527 }
528
529 fn gen_variable_reassignment(
530 &mut self,
531 variable: &VariableRef,
532 mut_or_immutable_expression: &Box<MutOrImmutableExpression>,
533 ctx: &Context,
534 ) {
535 self.gen_variable_assignment(variable, mut_or_immutable_expression, ctx);
536 }
537
538 fn gen_lvalue_address(
539 &mut self,
540 location_expression: &SingleLocationExpression,
541 ) -> FrameMemoryRegion {
542 let frame_relative_base_address = self
543 .variable_offsets
544 .get(
545 &location_expression
546 .starting_variable
547 .unique_id_within_function,
548 )
549 .unwrap();
550
551 *frame_relative_base_address
552
553 }
573
574 fn copy_back_mutable_arguments(
575 &mut self,
576 signature: &Signature,
577 maybe_self: Option<FrameMemoryRegion>,
578 arguments: &Vec<ArgumentExpressionOrLocation>,
579 ) {
580 let arguments_memory_region = self.infinite_above_frame_size();
581 let mut arguments_allocator = ScopeAllocator::new(arguments_memory_region);
582
583 let _argument_addr = Self::reserve(&signature.return_type, &mut arguments_allocator);
584
585 let mut parameters = signature.parameters.clone();
586 if let Some(found_self) = maybe_self {
587 let source_region =
588 Self::reserve(¶meters[0].resolved_type, &mut arguments_allocator);
589 self.state.builder.add_mov(
590 found_self.addr,
591 source_region.addr,
592 source_region.size,
593 "copy back to <self>",
594 );
595 parameters.remove(0);
596 }
597 for (parameter, argument) in parameters.iter().zip(arguments) {
598 let source_region = Self::reserve(¶meter.resolved_type, &mut arguments_allocator);
599 if !parameter.is_mutable {
600 continue;
601 }
602
603 if let ArgumentExpressionOrLocation::Location(found_location) = argument {
604 let argument_target = self.gen_lvalue_address(found_location);
605 self.state.builder.add_mov(
606 argument_target.addr,
607 source_region.addr,
608 source_region.size,
609 &format!(
610 "copy back mutable argument {}",
611 found_location.starting_variable.assigned_name
612 ),
613 );
614 } else {
615 panic!("internal error. argument is mut but not a location")
616 }
617 }
618 }
619 fn gen_arguments(
620 &mut self,
621 signature: &Signature,
622 self_region: Option<FrameMemoryRegion>,
623 arguments: &Vec<ArgumentExpressionOrLocation>,
624 ) {
625 let arguments_memory_region = self.infinite_above_frame_size();
626 let mut arguments_allocator = ScopeAllocator::new(arguments_memory_region);
627
628 let _argument_addr = Self::reserve(&signature.return_type, &mut arguments_allocator);
629
630 let mut argument_targets = Vec::new();
631 let mut argument_comments = Vec::new();
632
633 for type_for_parameter in &signature.parameters {
634 let argument_target =
635 Self::reserve(&type_for_parameter.resolved_type, &mut arguments_allocator);
636 let arg_ctx = Context::new(argument_target);
637 argument_targets.push(arg_ctx);
638 argument_comments.push(format!("argument {}", type_for_parameter.name));
639 }
640
641 if let Some(push_self) = self_region {
642 self.state.builder.add_mov(
643 argument_targets[0].addr(),
644 push_self.addr,
645 push_self.size,
646 "<self>",
647 );
648 argument_targets.remove(0);
649 }
650
651 for ((argument_target_ctx, argument_expr_or_loc), argument_comment) in argument_targets
652 .iter()
653 .zip(arguments)
654 .zip(argument_comments)
655 {
656 self.gen_argument(
657 argument_expr_or_loc,
658 &argument_target_ctx,
659 &argument_comment,
660 );
661 }
662 }
663
664 fn gen_postfix_chain(
665 &mut self,
666 start_expression: &Expression,
667 chain: &[Postfix],
668 ctx: &Context,
669 ) {
670 if let ExpressionKind::InternalFunctionAccess(internal_fn) = &start_expression.kind {
671 if chain.len() == 1 {
672 if let PostfixKind::FunctionCall(args) = &chain[0].kind {
673 self.gen_arguments(&internal_fn.signature, None, args);
674 self.state
675 .add_call(internal_fn, &format!("frame size: {}", self.frame_size)); let (return_size, _alignment) =
677 type_size_and_alignment(&internal_fn.signature.return_type);
678 if return_size.0 != 0 {
679 self.state.builder.add_mov(
680 ctx.addr(),
681 self.infinite_above_frame_size().addr,
682 return_size,
683 "copy the return value to destination",
684 );
685 }
686 self.copy_back_mutable_arguments(&internal_fn.signature, None, args);
687
688 return;
689 }
690 }
691 }
692
693 let start_source = self.gen_expression_for_access(start_expression, ctx);
694
695 for element in chain {
696 match &element.kind {
697 PostfixKind::StructField(_, _) => todo!(),
698 PostfixKind::MemberCall(function_to_call, arguments) => {
699 match &**function_to_call {
700 Function::Internal(internal_fn) => {
701 self.gen_arguments(
702 &internal_fn.signature,
703 Some(start_source),
704 arguments,
705 );
706 self.state
707 .add_call(internal_fn, &format!("frame size: {}", self.frame_size)); let (return_size, _alignment) =
709 type_size_and_alignment(&internal_fn.signature.return_type);
710 if return_size.0 != 0 {
711 self.state.builder.add_mov(
712 ctx.addr(),
713 self.infinite_above_frame_size().addr,
714 return_size,
715 "copy the return value to destination",
716 );
717 }
718
719 self.copy_back_mutable_arguments(
720 &internal_fn.signature,
721 Some(start_source),
722 arguments,
723 );
724 }
725 Function::External(external_fn) => {
726 }
728 }
729 }
730 PostfixKind::FunctionCall(arguments) => {
731 }
734 PostfixKind::OptionUnwrap => todo!(),
735 PostfixKind::NoneCoalesce(_) => todo!(),
736 PostfixKind::IntrinsicCall(_, _) => todo!(),
737 }
738 }
739 }
740
741 fn gen_tuple(&mut self, expressions: &[Expression], ctx: &Context) {
742 let mut scope = ScopeAllocator::new(ctx.target());
743
744 for expr in expressions {
745 let (memory_size, alignment) = type_size_and_alignment(&expr.ty);
746 let start_addr = scope.allocate(memory_size, alignment);
747 let element_region = FrameMemoryRegion::new(start_addr, memory_size);
748 let element_ctx = Context::new(element_region);
749 self.gen_expression(expr, &element_ctx);
750 }
751 }
752
753 fn get_struct_field_offset(
754 fields: &SeqMap<String, StructTypeField>,
755 index_to_find: usize,
756 ) -> MemoryOffset {
757 let mut offset = 0;
758
759 for (index, (_name, field)) in fields.iter().enumerate() {
760 if index == index_to_find {
761 break;
762 }
763
764 let (struct_field, struct_field_align) = type_size_and_alignment(&field.field_type);
765 offset += struct_field.0;
766 }
767
768 MemoryOffset(offset)
769 }
770
771 fn gen_anonymous_struct(
772 &mut self,
773 anon_struct_type: &AnonymousStructType,
774 source_order_expressions: &Vec<(usize, Expression)>,
775 base_context: &Context,
776 ) {
777 for (field_index, expression) in source_order_expressions {
778 let field_memory_offset = Self::get_struct_field_offset(
779 &anon_struct_type.field_name_sorted_fields,
780 *field_index,
781 );
782 let mut field_ctx = base_context.with_offset(MemorySize(field_memory_offset.0));
783 self.gen_expression(expression, &mut field_ctx);
784 }
785 }
786
787 fn gen_literal(&mut self, literal: &Literal, ctx: &Context) {
788 match literal {
789 Literal::IntLiteral(int) => {
790 self.state
791 .builder
792 .add_ld_imm_i32(ctx.addr(), *int, "int literal");
793 }
794 Literal::FloatLiteral(fixed_point) => {
795 self.state
796 .builder
797 .add_ld_imm_i32(ctx.addr(), fixed_point.inner(), "float literal");
798 }
799 Literal::NoneLiteral => {
800 self.state
801 .builder
802 .add_ld_imm_u8(ctx.addr(), 0, "none literal");
803 }
804 Literal::BoolLiteral(truthy) => {
805 self.state
806 .builder
807 .add_ld_imm_u8(ctx.addr(), u8::from(*truthy), "bool literal");
808 }
809
810 Literal::EnumVariantLiteral(enum_type, a, b) => {
811 self.state.builder.add_ld_imm_u8(
812 ctx.addr(),
813 a.common().container_index,
814 &format!("enum variant {} tag", a.common().assigned_name),
815 );
816
817 let starting_offset = MemoryOffset(1);
818
819 let (data_size, data_alignment) = match a {
820 EnumVariantType::Struct(enum_variant_struct) => {
821 layout_struct(&enum_variant_struct.anon_struct)
822 }
823 EnumVariantType::Tuple(tuple_type) => layout_tuple(&tuple_type.fields_in_order),
824 EnumVariantType::Nothing(_) => (MemorySize(0), MemoryAlignment::U8),
825 };
826
827 let skip_octets: usize = data_alignment.into();
828 let skip = MemorySize(skip_octets as u16);
829 let inner_addr = ctx.addr().add(skip);
830 let region = FrameMemoryRegion::new(inner_addr, data_size);
831 let inner_ctx = Context::new(region);
832
833 match b {
835 EnumLiteralData::Nothing => {}
836 EnumLiteralData::Tuple(expressions) => {
837 self.gen_tuple(expressions, &inner_ctx);
838 }
839 EnumLiteralData::Struct(sorted_expressions) => {
840 if let EnumVariantType::Struct(variant_struct_type) = a {
841 self.gen_anonymous_struct(
842 &variant_struct_type.anon_struct,
843 sorted_expressions,
844 &inner_ctx,
845 );
846 }
847 }
848 }
849 }
850 Literal::TupleLiteral(_, _) => {}
851 Literal::StringLiteral(str) => {
852 self.gen_string_literal(str, ctx);
853 }
854 Literal::Slice(_, _) => {}
855 Literal::SlicePair(_, _) => {}
856 }
857 }
858
859 fn gen_string_literal(&mut self, string: &str, ctx: &Context) {
860 let data_ptr = self
861 .state
862 .constants
863 .allocate(string.as_bytes(), MemoryAlignment::U8);
864 let mem_size = MemorySize(string.len() as u16);
865
866 self.gen_vec_immediate(data_ptr, mem_size, mem_size, "string", ctx);
867 }
868
869 fn gen_vec_immediate(
870 &mut self,
871 data_ptr: MemoryAddress,
872 len: MemorySize,
873 capacity: MemorySize,
874 comment_prefix: &str,
875 ctx: &Context,
876 ) {
877 self.state
878 .builder
879 .add_ld_u16(ctx.addr(), len.0, &format!("{} len", comment_prefix));
880
881 self.state.builder.add_ld_u16(
882 ctx.addr().add(MemorySize(2)),
883 capacity.0,
884 &format!("{} capacity", comment_prefix),
885 );
886
887 self.state.builder.add_ld_u16(
888 ctx.addr().add(MemorySize(4)),
889 data_ptr.0,
890 &format!("{} ptr", comment_prefix),
891 );
892 }
893
894 fn gen_option_expression(&mut self, maybe_option: Option<&Expression>, ctx: &Context) {
895 if let Some(found_value) = maybe_option {
896 self.state
897 .builder
898 .add_ld_imm_u8(ctx.addr(), 1, "option Some tag"); let mut one_offset_ctx = ctx.with_offset(MemorySize(1));
900 self.gen_expression(found_value, &mut one_offset_ctx); } else {
902 self.state
903 .builder
904 .add_ld_imm_u8(ctx.addr(), 0, "option None tag"); }
907 }
908
909 fn gen_for_loop(
910 &mut self,
911 for_pattern: &ForPattern,
912 iterable: &Iterable,
913 body: &Box<Expression>,
914 ctx: &Context,
915 ) {
916 match for_pattern {
923 ForPattern::Single(value_variable) => {}
924 ForPattern::Pair(key_variable, value_variable) => {}
925 }
926
927 let mut unit_expr = self.temp_space_for_type(&Type::Unit, "for loop body");
928 self.gen_expression(body, &mut unit_expr);
929
930 }
933
934 fn gen_for_loop_for_vec(
935 &mut self,
936 element_type: &Type,
937 vector_expr: Expression,
938 ctx: &mut Context,
939 ) {
940 let mut vector_ctx = self.temp_space_for_type(&vector_expr.ty, "vector space");
942 self.gen_expression(&vector_expr, &mut vector_ctx);
943
944 }
1028
1029 fn gen_block(&mut self, expressions: &[Expression], ctx: &Context) {
1030 if let Some((last, others)) = expressions.split_last() {
1031 for expr in others {
1032 let mut temp_context = self.temp_space_for_type(&Type::Unit, "block target");
1033 self.gen_expression(expr, &mut temp_context);
1034 }
1035 self.gen_expression(last, ctx);
1036 }
1037 }
1038
1039 fn gen_variable_access(&mut self, variable: &VariableRef, ctx: &Context) {
1040 let frame_address = self
1041 .variable_offsets
1042 .get(&variable.unique_id_within_function)
1043 .unwrap();
1044 let (size, _align) = type_size_and_alignment(&variable.resolved_type);
1045 self.state.builder.add_mov(
1046 ctx.addr(),
1047 frame_address.addr,
1048 size,
1049 &format!(
1050 "variable access '{}' ({})",
1051 variable.assigned_name,
1052 ctx.comment()
1053 ),
1054 );
1055 }
1056
1057 fn referenced_or_not_type(ty: &Type) -> Type {
1058 if let Type::MutableReference(inner_type) = ty {
1059 *inner_type.clone()
1060 } else {
1061 ty.clone()
1062 }
1063 }
1064
1065 fn compound_assignment(
1066 &mut self,
1067 target_location: &SingleMutLocationExpression,
1068 op: &CompoundOperatorKind,
1069 source: &Expression,
1070 ctx: &Context,
1071 ) {
1072 let target_location = self.gen_lvalue_address(&target_location.0);
1073
1074 let source_info = self.gen_expression_for_access(source, ctx);
1075
1076 let type_to_consider = Self::referenced_or_not_type(&source.ty);
1077
1078 match &type_to_consider {
1079 Type::Int => {
1080 self.gen_compound_assignment_i32(&target_location, op, &source_info);
1081 }
1082 Type::Float => todo!(),
1083 Type::String => todo!(),
1084 Type::Bool => todo!(),
1085 Type::Unit => todo!(),
1086 Type::Never => todo!(),
1087 Type::Tuple(_) => todo!(),
1088 Type::NamedStruct(_) => todo!(),
1089 Type::AnonymousStruct(_) => todo!(),
1090 Type::Enum(_) => todo!(),
1091 Type::Function(_) => todo!(),
1092 Type::Iterable(_) => todo!(),
1093 Type::Optional(_) => todo!(),
1094 Type::Generic(_, _) => todo!(),
1095 Type::Blueprint(_) => todo!(),
1096 Type::Variable(_) => todo!(),
1097 Type::External(_) => todo!(),
1098 Type::MutableReference(x) => panic!("should have been checked"),
1099 }
1100 }
1101
1102 fn gen_compound_assignment_i32(
1103 &mut self,
1104 target: &FrameMemoryRegion,
1105 op: &CompoundOperatorKind,
1106 source_ctx: &FrameMemoryRegion,
1107 ) {
1108 match op {
1109 CompoundOperatorKind::Add => {
1110 self.state.builder.add_add_i32(
1111 target.addr(),
1112 target.addr(),
1113 source_ctx.addr(),
1114 "+= (i32)",
1115 );
1116 }
1117 CompoundOperatorKind::Sub => todo!(),
1118 CompoundOperatorKind::Mul => todo!(),
1119 CompoundOperatorKind::Div => todo!(),
1120 CompoundOperatorKind::Modulo => todo!(),
1121 }
1122 }
1123
1124 fn internal_function_access(
1125 &mut self,
1126 internal: &InternalFunctionDefinitionRef,
1127 ctx: &Context,
1128 ) {
1129 self.state.builder.add_ld_u16(
1130 ctx.addr(),
1131 internal.program_unique_id,
1132 &format!("function access '{}'", internal.assigned_name),
1133 );
1134 }
1135
1136 fn infinite_above_frame_size(&self) -> FrameMemoryRegion {
1137 FrameMemoryRegion::new(FrameMemoryAddress(self.frame_size.0), MemorySize(1024))
1138 }
1139
1140 fn gen_struct_literal(&mut self, struct_literal: &StructInstantiation, ctx: &Context) {
1141 let struct_type =
1142 Type::AnonymousStruct(struct_literal.struct_type_ref.anon_struct_type.clone());
1143 let (whole_struct_size, whole_struct_alignment) = type_size_and_alignment(&struct_type);
1144 if ctx.target_size().0 != whole_struct_size.0 {
1145 info!("problem");
1146 }
1147 assert_eq!(ctx.target_size().0, whole_struct_size.0);
1148
1149 for (field_index, expression) in &struct_literal.source_order_expressions {
1150 let (field_offset, field_size, field_alignment) = struct_field_offset(
1151 *field_index,
1152 &struct_literal.struct_type_ref.anon_struct_type,
1153 );
1154 let new_address = ctx.addr().advance(field_offset);
1156 let mut field_ctx = Context::new(FrameMemoryRegion::new(new_address, field_size));
1157 self.gen_expression(expression, &mut field_ctx);
1158 }
1159 }
1160
1161 fn gen_intrinsic_call_ex(
1162 &self,
1163 intrinsic_fn: &IntrinsicFunction,
1164 arguments: &Vec<ArgumentExpressionOrLocation>,
1165 ctx: &Context,
1166 ) {
1167 match intrinsic_fn {
1170 IntrinsicFunction::FloatRound => {}
1171 IntrinsicFunction::FloatFloor => {}
1172 IntrinsicFunction::FloatSqrt => {}
1173 IntrinsicFunction::FloatSign => {}
1174 IntrinsicFunction::FloatAbs => {}
1175 IntrinsicFunction::FloatRnd => {}
1176 IntrinsicFunction::FloatCos => {}
1177 IntrinsicFunction::FloatSin => {}
1178 IntrinsicFunction::FloatAcos => {}
1179 IntrinsicFunction::FloatAsin => {}
1180 IntrinsicFunction::FloatAtan2 => {}
1181 IntrinsicFunction::FloatMin => {}
1182 IntrinsicFunction::FloatMax => {}
1183 IntrinsicFunction::FloatClamp => {}
1184 IntrinsicFunction::IntAbs => {}
1185 IntrinsicFunction::IntRnd => {}
1186 IntrinsicFunction::IntMax => {}
1187 IntrinsicFunction::IntMin => {}
1188 IntrinsicFunction::IntClamp => {}
1189 IntrinsicFunction::IntToFloat => {}
1190 IntrinsicFunction::StringLen => {}
1191 IntrinsicFunction::VecFromSlice => {}
1192 IntrinsicFunction::VecPush => {}
1193 IntrinsicFunction::VecPop => {}
1194 IntrinsicFunction::VecRemoveIndex => {}
1195 IntrinsicFunction::VecClear => {}
1196 IntrinsicFunction::VecCreate => {}
1197 IntrinsicFunction::VecSubscript => {}
1198 IntrinsicFunction::VecSubscriptMut => {}
1199 IntrinsicFunction::VecIter => {}
1200 IntrinsicFunction::VecIterMut => {}
1201 IntrinsicFunction::VecSelfPush => {}
1202 IntrinsicFunction::VecSelfExtend => {}
1203 IntrinsicFunction::MapCreate => {}
1204 IntrinsicFunction::MapFromSlicePair => {}
1205 IntrinsicFunction::MapHas => {}
1206 IntrinsicFunction::MapRemove => {}
1207 IntrinsicFunction::MapIter => {}
1208 IntrinsicFunction::MapIterMut => {}
1209 IntrinsicFunction::MapLen => {}
1210 IntrinsicFunction::MapIsEmpty => {}
1211 IntrinsicFunction::MapSubscript => {}
1212 IntrinsicFunction::MapSubscriptSet => {}
1213 IntrinsicFunction::MapSubscriptMut => {}
1214 IntrinsicFunction::MapSubscriptMutCreateIfNeeded => {}
1215 IntrinsicFunction::SparseCreate => {}
1216 IntrinsicFunction::SparseFromSlice => {}
1217 IntrinsicFunction::SparseIter => {}
1218 IntrinsicFunction::SparseIterMut => {}
1219 IntrinsicFunction::SparseSubscript => {}
1220 IntrinsicFunction::SparseSubscriptMut => {}
1221 IntrinsicFunction::SparseHas => {}
1222 IntrinsicFunction::SparseRemove => {}
1223 IntrinsicFunction::GridCreate => {}
1224 IntrinsicFunction::GridFromSlice => {}
1225 IntrinsicFunction::GridSubscript => {}
1226 IntrinsicFunction::GridSubscriptMut => {}
1227 IntrinsicFunction::Float2Magnitude => {}
1228 IntrinsicFunction::SparseAdd => {}
1229 IntrinsicFunction::VecLen => {}
1230 IntrinsicFunction::VecIsEmpty => {}
1231 IntrinsicFunction::SparseNew => {}
1232 }
1233 }
1234}
1235
1236fn struct_field_offset(
1237 index_to_look_for: usize,
1238 anon_struct_type: &AnonymousStructType,
1239) -> (MemoryOffset, MemorySize, MemoryAlignment) {
1240 let mut offset = MemoryOffset(0);
1241 for (field_index, (_name, field)) in
1242 anon_struct_type.field_name_sorted_fields.iter().enumerate()
1243 {
1244 let (field_size, field_alignment) = type_size_and_alignment(&field.field_type);
1245 let field_start_offset = offset.space(field_size, field_alignment);
1246 if field_index == index_to_look_for {
1247 return (field_start_offset, field_size, field_alignment);
1248 }
1249 }
1250
1251 panic!("field index is wrong")
1252}