swamp_script_code_gen/
lib.rs

1pub mod alloc;
2pub mod alloc_util;
3pub mod constants;
4pub mod ctx;
5mod location;
6mod vec;
7
8use crate::alloc::{ConstantMemoryRegion, FrameMemoryRegion, ScopeAllocator};
9use crate::alloc_util::{
10    is_map, is_vec, layout_struct, layout_tuple, layout_tuple_elements, reserve_space_for_type,
11    type_size_and_alignment,
12};
13use crate::constants::ConstantsManager;
14use crate::ctx::Context;
15use seq_map::SeqMap;
16use std::path::PathBuf;
17use swamp_script_node::Node;
18use swamp_script_semantic::intr::IntrinsicFunction;
19use swamp_script_semantic::{
20    AnonymousStructLiteral, ArgumentExpressionOrLocation, BinaryOperator, BinaryOperatorKind,
21    BooleanExpression, CompoundOperatorKind, ConstantId, ConstantRef, EnumLiteralData, Expression,
22    ExpressionKind, ForPattern, Function, Guard, InternalFunctionDefinitionRef, InternalFunctionId,
23    InternalMainExpression, Iterable, Literal, Match, MutOrImmutableExpression, NormalPattern,
24    Pattern, Postfix, PostfixKind, SingleLocationExpression, SingleMutLocationExpression,
25    StructInstantiation, UnaryOperator, UnaryOperatorKind, VariableRef, WhenBinding,
26};
27use swamp_script_source_map_lookup::{SourceMapLookup, SourceMapWrapper};
28use swamp_script_types::{AnonymousStructType, EnumVariantType, Signature, StructTypeField, Type};
29use swamp_vm_disasm::{disasm_color, disasm_instructions_color};
30use swamp_vm_instr_build::{InstructionBuilder, PatchPosition};
31use swamp_vm_types::{
32    BOOL_SIZE, BinaryInstruction, CountU16, FrameMemoryAddress, FrameMemoryAddressIndirectPointer,
33    FrameMemorySize, HEAP_PTR_ALIGNMENT, HEAP_PTR_SIZE, HeapMemoryAddress, INT_SIZE,
34    InstructionPosition, MemoryAlignment, MemoryOffset, MemorySize, PTR_SIZE,
35    TempFrameMemoryAddress, VEC_ITERATOR_ALIGNMENT, VEC_ITERATOR_SIZE,
36};
37use tracing::{error, info, trace};
38
39pub struct GeneratedExpressionResult {
40    pub has_set_bool_z_flag: bool,
41}
42
43impl Default for GeneratedExpressionResult {
44    fn default() -> Self {
45        Self {
46            has_set_bool_z_flag: false,
47        }
48    }
49}
50
51#[derive(Debug)]
52pub enum ErrorKind {
53    IllegalCompoundAssignment,
54    VariableNotUnique,
55    IllegalCollection,
56    NotAnIterableCollection,
57}
58
59#[derive(Debug)]
60pub struct Error {
61    pub kind: ErrorKind,
62    pub node: Node,
63}
64
65pub struct SlicePairInfo {
66    pub addr: TempFrameMemoryAddress,
67    pub key_size: MemorySize,
68    pub value_size: MemorySize,
69    pub element_count: CountU16,
70    pub element_size: MemorySize,
71}
72
73pub struct FunctionInfo {
74    pub starts_at_ip: InstructionPosition,
75    pub internal_function_definition: InternalFunctionDefinitionRef,
76}
77
78pub struct FunctionFixup {
79    pub patch_position: PatchPosition,
80    pub fn_id: InternalFunctionId,
81    //pub internal_function_definition: InternalFunctionDefinitionRef,
82}
83
84pub struct ConstantInfo {
85    pub ip: InstructionPosition,
86    pub constant_ref: ConstantRef,
87    pub target_constant_memory: ConstantMemoryRegion,
88}
89
90pub struct CodeGenState {
91    builder: InstructionBuilder,
92    constants: ConstantsManager,
93    constant_offsets: SeqMap<ConstantId, ConstantMemoryRegion>,
94    constant_functions: SeqMap<ConstantId, ConstantInfo>,
95    function_infos: SeqMap<InternalFunctionId, FunctionInfo>,
96    function_fixups: Vec<FunctionFixup>,
97    //source_map_lookup: &'b SourceMapWrapper<'b>,
98    debug_last_ip: usize,
99}
100
101pub struct GenOptions {
102    pub is_halt_function: bool,
103}
104
105impl CodeGenState {
106    #[must_use]
107    pub fn new() -> Self {
108        Self {
109            builder: InstructionBuilder::default(),
110            constants: ConstantsManager::new(),
111            constant_offsets: SeqMap::default(),
112            function_infos: SeqMap::default(),
113            constant_functions: SeqMap::default(),
114            function_fixups: vec![],
115            debug_last_ip: 0,
116        }
117    }
118
119    #[must_use]
120    pub fn instructions(&self) -> &[BinaryInstruction] {
121        &self.builder.instructions
122    }
123    pub fn create_function_sections(&self) -> SeqMap<InstructionPosition, String> {
124        let mut lookups = SeqMap::new();
125        for (_func_id, function_info) in &self.function_infos {
126            let description = function_info
127                .internal_function_definition
128                .assigned_name
129                .clone();
130            lookups
131                .insert(function_info.starts_at_ip.clone(), description)
132                .unwrap();
133        }
134
135        for (_func_id, function_info) in &self.constant_functions {
136            let description = format!("constant {}", function_info.constant_ref.assigned_name);
137            lookups
138                .insert(function_info.ip.clone(), description)
139                .unwrap();
140        }
141
142        lookups
143    }
144    #[must_use]
145    pub fn builder(&self) -> &InstructionBuilder {
146        &self.builder
147    }
148    pub fn constant_functions(&self) -> &SeqMap<ConstantId, ConstantInfo> {
149        &self.constant_functions
150    }
151    pub(crate) fn add_call(&mut self, internal_fn: &InternalFunctionDefinitionRef, comment: &str) {
152        let call_comment = &format!("calling {} ({})", internal_fn.assigned_name, comment);
153
154        if let Some(found) = self.function_infos.get(&internal_fn.program_unique_id) {
155            self.builder.add_call(&found.starts_at_ip, call_comment);
156        } else {
157            let patch_position = self.builder.add_call_placeholder(call_comment);
158            self.function_fixups.push(FunctionFixup {
159                patch_position,
160                fn_id: internal_fn.program_unique_id,
161            });
162        }
163    }
164    #[must_use]
165    pub fn comments(&self) -> &[String] {
166        &self.builder.comments
167    }
168
169    pub fn finalize(&mut self) {
170        for function_fixup in &self.function_fixups {
171            let func = self.function_infos.get(&function_fixup.fn_id).unwrap();
172            self.builder.patch_call(
173                PatchPosition(InstructionPosition(function_fixup.patch_position.0.0)),
174                &func.starts_at_ip,
175            );
176        }
177    }
178
179    #[must_use]
180    pub fn take_instructions_and_constants(
181        self,
182    ) -> (
183        Vec<BinaryInstruction>,
184        Vec<u8>,
185        SeqMap<ConstantId, ConstantInfo>,
186    ) {
187        (
188            self.builder.instructions,
189            self.constants.take_data(),
190            self.constant_functions,
191        )
192    }
193
194    pub fn gen_function_def(
195        &mut self,
196        internal_fn_def: &InternalFunctionDefinitionRef,
197        options: &GenOptions,
198        source_map_wrapper: &SourceMapWrapper,
199    ) -> Result<(), Error> {
200        assert_ne!(internal_fn_def.program_unique_id, 0);
201        self.function_infos
202            .insert(
203                internal_fn_def.program_unique_id,
204                FunctionInfo {
205                    starts_at_ip: self.builder.position(),
206                    internal_function_definition: internal_fn_def.clone(),
207                },
208            )
209            .unwrap();
210
211        let mut function_generator = FunctionCodeGen::new(self, source_map_wrapper);
212
213        function_generator.layout_variables(
214            &internal_fn_def.function_scope_state,
215            &internal_fn_def.signature.return_type,
216        )?;
217
218        let ExpressionKind::Block(block_expressions) = &internal_fn_def.body.kind else {
219            panic!("function body should be a block")
220        };
221
222        if let ExpressionKind::IntrinsicCallEx(found_intrinsic_fn, _non_instantiated_arguments) =
223            &block_expressions[0].kind
224        {
225            // Intentionally do nothing
226            todo!()
227        } else {
228            let (return_type_size, _return_alignment) =
229                type_size_and_alignment(&internal_fn_def.signature.return_type);
230            let ctx = Context::new(FrameMemoryRegion::new(
231                FrameMemoryAddress(0),
232                return_type_size,
233            ));
234            function_generator.gen_expression(&internal_fn_def.body, &ctx)?;
235        }
236
237        self.finalize_function(options);
238
239        Ok(())
240    }
241
242    pub fn finalize_function(&mut self, options: &GenOptions) {
243        if options.is_halt_function {
244            self.builder.add_hlt("");
245        } else {
246            self.builder.add_ret("");
247        }
248    }
249
250    pub fn reserve_space_for_constants(&mut self, constants: &[ConstantRef]) -> Result<(), Error> {
251        for constant in constants {
252            let (size, alignment) = type_size_and_alignment(&constant.resolved_type);
253
254            let constant_memory_address = self.constants.reserve(size, alignment);
255
256            let constant_memory_region = ConstantMemoryRegion {
257                addr: constant_memory_address,
258                size,
259            };
260
261            self.constant_offsets
262                .insert(constant.id, constant_memory_region)
263                .unwrap();
264        }
265
266        Ok(())
267    }
268    pub fn gen_constants_expression_functions_in_order(
269        &mut self,
270        constants: &[ConstantRef],
271        source_map_wrapper: &SourceMapWrapper,
272    ) -> Result<(), Error> {
273        for constant in constants {
274            let target_region = *self.constant_offsets.get(&constant.id).unwrap();
275            let ip = self.builder.position();
276            {
277                let mut function_generator = FunctionCodeGen::new(self, source_map_wrapper);
278
279                let constant_target_ctx = Context::new(FrameMemoryRegion::new(
280                    FrameMemoryAddress(0),
281                    target_region.size,
282                ));
283                function_generator.gen_expression(&constant.expr, &constant_target_ctx)?;
284                self.finalize_function(&GenOptions {
285                    is_halt_function: true,
286                });
287            }
288
289            let constant_info = ConstantInfo {
290                ip,
291                target_constant_memory: target_region,
292                constant_ref: constant.clone(),
293            };
294
295            self.constant_functions
296                .insert(constant.id, constant_info)
297                .unwrap();
298        }
299
300        Ok(())
301    }
302
303    /// # Errors
304    ///
305    pub fn gen_main_function(
306        &mut self,
307        main: &InternalMainExpression,
308        options: &GenOptions,
309        source_map_lookup: &SourceMapWrapper,
310    ) -> Result<(), Error> {
311        let mut function_generator = FunctionCodeGen::new(self, source_map_lookup);
312
313        function_generator.layout_variables(&main.function_scope_state, &main.expression.ty)?;
314        let empty_ctx = Context::new(FrameMemoryRegion::default());
315        function_generator.gen_expression(&main.expression, &empty_ctx)?;
316        self.finalize_function(options);
317        Ok(())
318    }
319}
320
321pub struct FunctionCodeGen<'a> {
322    state: &'a mut CodeGenState,
323    variable_offsets: SeqMap<usize, FrameMemoryRegion>,
324    frame_size: FrameMemorySize,
325    //extra_frame_allocator: ScopeAllocator,
326    temp_allocator: ScopeAllocator,
327    argument_allocator: ScopeAllocator,
328    source_map_lookup: &'a SourceMapWrapper<'a>,
329}
330
331impl<'a> FunctionCodeGen<'a> {
332    #[must_use]
333    pub fn new(state: &'a mut CodeGenState, source_map_lookup: &'a SourceMapWrapper) -> Self {
334        Self {
335            state,
336            variable_offsets: SeqMap::default(),
337            frame_size: FrameMemorySize(0),
338            //  extra_frame_allocator: ScopeAllocator::new(FrameMemoryRegion::default()),
339            temp_allocator: ScopeAllocator::new(FrameMemoryRegion::default()),
340            argument_allocator: ScopeAllocator::new(FrameMemoryRegion::default()),
341            source_map_lookup,
342        }
343    }
344}
345
346impl FunctionCodeGen<'_> {
347    #[allow(clippy::too_many_lines)]
348    pub(crate) fn gen_single_intrinsic_call(
349        &mut self,
350        intrinsic_fn: &IntrinsicFunction,
351        self_addr: Option<FrameMemoryRegion>,
352        arguments: &[ArgumentExpressionOrLocation],
353        ctx: &Context,
354    ) -> Result<(), Error> {
355        match intrinsic_fn {
356            // Fixed
357            IntrinsicFunction::FloatRound => todo!(),
358            IntrinsicFunction::FloatFloor => todo!(),
359            IntrinsicFunction::FloatSqrt => todo!(),
360            IntrinsicFunction::FloatSign => todo!(),
361            IntrinsicFunction::FloatAbs => todo!(),
362            IntrinsicFunction::FloatRnd => todo!(),
363            IntrinsicFunction::FloatCos => todo!(),
364            IntrinsicFunction::FloatSin => todo!(),
365            IntrinsicFunction::FloatAcos => todo!(),
366            IntrinsicFunction::FloatAsin => todo!(),
367            IntrinsicFunction::FloatAtan2 => todo!(),
368            IntrinsicFunction::FloatMin => todo!(),
369            IntrinsicFunction::FloatMax => todo!(),
370            IntrinsicFunction::FloatClamp => todo!(),
371            // Int
372            IntrinsicFunction::IntAbs => todo!(),
373            IntrinsicFunction::IntRnd => todo!(),
374            IntrinsicFunction::IntMax => todo!(),
375            IntrinsicFunction::IntMin => todo!(),
376            IntrinsicFunction::IntClamp => todo!(),
377            IntrinsicFunction::IntToFloat => todo!(),
378
379            // String
380            IntrinsicFunction::StringLen => {
381                self.state.builder.add_string_len(
382                    ctx.addr(),
383                    FrameMemoryAddressIndirectPointer(self_addr.unwrap().addr),
384                    "get the length",
385                );
386                Ok(())
387            }
388
389            // Vec
390            IntrinsicFunction::VecFromSlice => {
391                let slice_variable = &arguments[0];
392                let slice_region = self.gen_for_access_or_location_ex(slice_variable)?;
393                let (element_size, element_alignment) =
394                    type_size_and_alignment(&slice_variable.ty());
395                self.state.builder.add_vec_from_slice(
396                    ctx.addr(),
397                    slice_region.addr,
398                    element_size,
399                    CountU16(slice_region.size.0 / element_size.0),
400                    "create vec from slice",
401                );
402                Ok(())
403            }
404            IntrinsicFunction::VecPush => todo!(),
405            IntrinsicFunction::VecPop => todo!(),
406            IntrinsicFunction::VecRemoveIndex => todo!(),
407            IntrinsicFunction::VecClear => todo!(),
408            IntrinsicFunction::VecCreate => todo!(),
409            IntrinsicFunction::VecSubscript => todo!(),
410            IntrinsicFunction::VecSubscriptMut => todo!(),
411            IntrinsicFunction::VecSubscriptRange => todo!(),
412            IntrinsicFunction::VecIter => todo!(),
413            IntrinsicFunction::VecIterMut => todo!(),
414            IntrinsicFunction::VecFor => todo!(),
415            IntrinsicFunction::VecSelfPush => todo!(),
416            IntrinsicFunction::VecSelfExtend => todo!(),
417            IntrinsicFunction::VecLen => todo!(),
418            IntrinsicFunction::VecIsEmpty => todo!(),
419
420            // Map
421            IntrinsicFunction::MapCreate => todo!(),
422            IntrinsicFunction::MapFromSlicePair => {
423                let slice_pair_argument = &arguments[0];
424                let ArgumentExpressionOrLocation::Expression(expr) = slice_pair_argument else {
425                    panic!();
426                };
427
428                let ExpressionKind::Literal(some_lit) = &expr.kind else {
429                    panic!();
430                };
431
432                let Literal::SlicePair(slice_type, expression_pairs) = some_lit else {
433                    panic!();
434                };
435
436                let slice_pair_info = self.gen_slice_pair_literal(slice_type, expression_pairs);
437                self.state.builder.add_map_new_from_slice(
438                    ctx.addr(),
439                    slice_pair_info.addr.to_addr(),
440                    slice_pair_info.key_size,
441                    slice_pair_info.value_size,
442                    slice_pair_info.element_count,
443                    "create map from temporary slice pair",
444                );
445
446                Ok(())
447            }
448            IntrinsicFunction::MapHas => todo!(),
449            IntrinsicFunction::MapRemove => {
450                let ArgumentExpressionOrLocation::Expression(key_argument) = &arguments[0] else {
451                    panic!("must be expression for key");
452                };
453                self.gen_intrinsic_map_remove(self_addr.unwrap(), key_argument, ctx)
454            }
455            IntrinsicFunction::MapIter => todo!(),
456            IntrinsicFunction::MapIterMut => todo!(),
457            IntrinsicFunction::MapLen => todo!(),
458            IntrinsicFunction::MapIsEmpty => todo!(),
459            IntrinsicFunction::MapSubscript => todo!(),
460            IntrinsicFunction::MapSubscriptSet => todo!(),
461            IntrinsicFunction::MapSubscriptMut => todo!(),
462            IntrinsicFunction::MapSubscriptMutCreateIfNeeded => todo!(),
463
464            // Map2
465            IntrinsicFunction::Map2Remove => todo!(),
466            IntrinsicFunction::Map2Insert => todo!(),
467            IntrinsicFunction::Map2GetColumn => todo!(),
468            IntrinsicFunction::Map2GetRow => todo!(),
469            IntrinsicFunction::Map2Get => todo!(),
470            IntrinsicFunction::Map2Has => todo!(),
471            IntrinsicFunction::Map2Create => todo!(),
472
473            // Sparse
474            IntrinsicFunction::SparseCreate => todo!(),
475            IntrinsicFunction::SparseFromSlice => todo!(),
476            IntrinsicFunction::SparseIter => todo!(),
477            IntrinsicFunction::SparseIterMut => todo!(),
478            IntrinsicFunction::SparseSubscript => todo!(),
479            IntrinsicFunction::SparseSubscriptMut => todo!(),
480            IntrinsicFunction::SparseHas => todo!(),
481            IntrinsicFunction::SparseRemove => todo!(),
482
483            // Grid
484            IntrinsicFunction::GridCreate => todo!(),
485            IntrinsicFunction::GridFromSlice => todo!(),
486            IntrinsicFunction::GridSet => todo!(),
487            IntrinsicFunction::GridGet => todo!(),
488            IntrinsicFunction::GridGetColumn => todo!(),
489
490            IntrinsicFunction::Float2Magnitude => todo!(),
491
492            IntrinsicFunction::SparseAdd => todo!(),
493            IntrinsicFunction::SparseNew => todo!(),
494        }
495    }
496
497    fn gen_intrinsic_map_remove(
498        &mut self,
499        map_region: FrameMemoryRegion,
500        key_expr: &Expression,
501        ctx: &Context,
502    ) -> Result<(), Error> {
503        let key_region = self.gen_expression_for_access(key_expr)?;
504
505        self.state
506            .builder
507            .add_map_remove(map_region.addr, key_region.addr, "");
508
509        Ok(())
510    }
511
512    pub fn reserve(ty: &Type, allocator: &mut ScopeAllocator) -> FrameMemoryRegion {
513        let (size, alignment) = type_size_and_alignment(ty);
514        allocator.reserve(size, alignment)
515    }
516
517    /// # Errors
518    ///
519    pub fn layout_variables(
520        &mut self,
521        variables: &Vec<VariableRef>,
522        return_type: &Type,
523    ) -> Result<(), Error> {
524        let mut allocator = ScopeAllocator::new(FrameMemoryRegion::new(
525            FrameMemoryAddress(0),
526            MemorySize(1024),
527        ));
528        let _current_offset = Self::reserve(return_type, &mut allocator);
529
530        let mut enter_comment = "variables:\n".to_string();
531
532        for var_ref in variables {
533            let var_target = Self::reserve(&var_ref.resolved_type, &mut allocator);
534            trace!(?var_ref.assigned_name, ?var_target, "laying out");
535            enter_comment += &format!(
536                "  ${:04X}:{} {}\n",
537                var_target.addr.0, var_target.size.0, var_ref.assigned_name
538            );
539            self.variable_offsets
540                .insert(var_ref.unique_id_within_function, var_target)
541                .map_err(|_| self.create_err(ErrorKind::VariableNotUnique, &var_ref.name))?;
542        }
543
544        let extra_frame_size = MemorySize(80);
545        let extra_target = FrameMemoryRegion::new(allocator.addr(), extra_frame_size);
546        self.frame_size = allocator.addr().as_size().add(extra_frame_size);
547
548        self.state
549            .builder
550            .add_enter(self.frame_size, &enter_comment);
551
552        const ARGUMENT_MAX_SIZE: u16 = 256;
553        self.argument_allocator = ScopeAllocator::new(FrameMemoryRegion::new(
554            FrameMemoryAddress(self.frame_size.0),
555            MemorySize(ARGUMENT_MAX_SIZE),
556        ));
557
558        self.temp_allocator = ScopeAllocator::new(FrameMemoryRegion::new(
559            FrameMemoryAddress(self.frame_size.0 + ARGUMENT_MAX_SIZE),
560            MemorySize(1024),
561        ));
562
563        Ok(())
564    }
565
566    pub fn temp_memory_region_for_type(&mut self, ty: &Type, comment: &str) -> FrameMemoryRegion {
567        let new_target_info = reserve_space_for_type(ty, &mut self.temp_allocator);
568        new_target_info
569    }
570
571    pub fn temp_space_for_type(&mut self, ty: &Type, comment: &str) -> Context {
572        Context::new(self.temp_memory_region_for_type(ty, comment))
573    }
574
575    /// # Panics
576    ///
577    #[allow(clippy::single_match_else)]
578    pub fn gen_expression_for_access(
579        &mut self,
580        expr: &Expression,
581    ) -> Result<FrameMemoryRegion, Error> {
582        let (region, _gen_result) = self.gen_expression_for_access_internal(expr)?;
583
584        Ok(region)
585    }
586
587    /// # Panics
588    ///
589    #[allow(clippy::single_match_else)]
590    pub fn gen_expression_for_access_internal(
591        &mut self,
592        expr: &Expression,
593    ) -> Result<(FrameMemoryRegion, GeneratedExpressionResult), Error> {
594        match &expr.kind {
595            ExpressionKind::VariableAccess(var_ref) => {
596                let frame_address = self
597                    .variable_offsets
598                    .get(&var_ref.unique_id_within_function)
599                    .unwrap();
600
601                return Ok((*frame_address, GeneratedExpressionResult::default()));
602            }
603
604            ExpressionKind::Literal(lit) => match lit {
605                Literal::Slice(slice_type, expressions) => {
606                    return Ok((
607                        self.gen_slice_literal(slice_type, expressions)?,
608                        GeneratedExpressionResult::default(),
609                    ));
610                }
611                Literal::SlicePair(slice_pair_type, pairs) => {
612                    let info = self.gen_slice_pair_literal(slice_pair_type, pairs);
613                    return Ok((
614                        FrameMemoryRegion::new(
615                            info.addr.0,
616                            MemorySize(info.element_count.0 * info.element_size.0),
617                        ),
618                        GeneratedExpressionResult::default(),
619                    ));
620                }
621                _ => {}
622            },
623            _ => {}
624        };
625
626        let temp_ctx = self.temp_space_for_type(&expr.ty, "expression");
627
628        let expression_result = self.gen_expression(expr, &temp_ctx)?;
629
630        Ok((temp_ctx.target(), expression_result))
631    }
632
633    pub(crate) fn extra_frame_space_for_type(&mut self, ty: &Type) -> Context {
634        let target = Self::reserve(ty, &mut self.temp_allocator);
635        Context::new(target)
636    }
637
638    fn debug_node(&self, node: &Node) {
639        let line_info = self.source_map_lookup.get_line(&node.span);
640        let span_text = self.source_map_lookup.get_text_span(&node.span);
641        eprintln!(
642            "{}:{}:{}> {}",
643            line_info.relative_file_name, line_info.row, line_info.col, span_text,
644        );
645        //info!(?source_code_line, "generating");
646    }
647
648    fn debug_instructions(&mut self) {
649        let end_ip = self.state.builder.instructions.len() - 1;
650        let instructions_to_disasm =
651            &self.state.builder.instructions[self.state.debug_last_ip..=end_ip];
652        let mut descriptions = Vec::new();
653        for x in instructions_to_disasm {
654            descriptions.push(String::new());
655        }
656        let output = disasm_instructions_color(
657            instructions_to_disasm,
658            &InstructionPosition(self.state.debug_last_ip as u16),
659            &descriptions,
660            &SeqMap::default(),
661        );
662        eprintln!("{output}");
663        self.state.debug_last_ip = end_ip + 1;
664    }
665
666    pub fn gen_expression(
667        &mut self,
668        expr: &Expression,
669        ctx: &Context,
670    ) -> Result<GeneratedExpressionResult, Error> {
671        self.debug_node(&expr.node);
672        let result = match &expr.kind {
673            ExpressionKind::InterpolatedString(_) => todo!(),
674
675            ExpressionKind::ConstantAccess(constant_ref) => self
676                .gen_constant_access(constant_ref, ctx)
677                .map(|_| GeneratedExpressionResult::default()),
678            ExpressionKind::TupleDestructuring(variables, tuple_types, tuple_expression) => self
679                .gen_tuple_destructuring(variables, tuple_types, tuple_expression)
680                .map(|_| GeneratedExpressionResult::default()),
681
682            ExpressionKind::Assignment(target_mut_location_expr, source_expr) => self
683                .gen_assignment(target_mut_location_expr, source_expr)
684                .map(|_| GeneratedExpressionResult::default()),
685            ExpressionKind::VariableAccess(variable_ref) => self
686                .gen_variable_access(variable_ref, ctx)
687                .map(|_| GeneratedExpressionResult::default()),
688            ExpressionKind::InternalFunctionAccess(function) => self
689                .internal_function_access(function, ctx)
690                .map(|_| GeneratedExpressionResult::default()),
691            ExpressionKind::BinaryOp(operator) => self.gen_binary_operator(operator, ctx),
692            ExpressionKind::UnaryOp(operator) => self
693                .gen_unary_operator(operator, ctx)
694                .map(|_| GeneratedExpressionResult::default()),
695            ExpressionKind::PostfixChain(start, chain) => self
696                .gen_postfix_chain(start, chain, ctx)
697                .map(|_| GeneratedExpressionResult::default()),
698            ExpressionKind::VariableDefinition(variable, expression) => self
699                .gen_variable_definition(variable, expression, ctx)
700                .map(|_| GeneratedExpressionResult::default()),
701            ExpressionKind::VariableReassignment(variable, expression) => self
702                .gen_variable_reassignment(variable, expression, ctx)
703                .map(|_| GeneratedExpressionResult::default()),
704            ExpressionKind::StructInstantiation(struct_literal) => self
705                .gen_struct_literal(struct_literal, ctx)
706                .map(|()| GeneratedExpressionResult::default()),
707            ExpressionKind::AnonymousStructLiteral(anon_struct) => self
708                .gen_anonymous_struct_literal(anon_struct, ctx)
709                .map(|_| GeneratedExpressionResult::default()),
710            ExpressionKind::Literal(basic_literal) => self
711                .gen_literal(basic_literal, ctx)
712                .map(|_| GeneratedExpressionResult::default()),
713            ExpressionKind::Option(maybe_option) => self
714                .gen_option_expression(maybe_option.as_deref(), ctx)
715                .map(|_| GeneratedExpressionResult::default()),
716            ExpressionKind::ForLoop(a, b, c) => self
717                .gen_for_loop(a, b, c)
718                .map(|_| GeneratedExpressionResult::default()),
719            ExpressionKind::WhileLoop(condition, expression) => self
720                .gen_while_loop(condition, expression, ctx)
721                .map(|_| GeneratedExpressionResult::default()),
722            ExpressionKind::Block(expressions) => self
723                .gen_block(expressions, ctx)
724                .map(|_| GeneratedExpressionResult::default()),
725            ExpressionKind::Match(match_expr) => self
726                .gen_match(match_expr, ctx)
727                .map(|_| GeneratedExpressionResult::default()),
728            ExpressionKind::Guard(guards) => self
729                .gen_guard(guards, ctx)
730                .map(|_| GeneratedExpressionResult::default()),
731            ExpressionKind::If(conditional, true_expr, false_expr) => self
732                .gen_if(conditional, true_expr, false_expr.as_deref(), ctx)
733                .map(|_| GeneratedExpressionResult::default()),
734            ExpressionKind::When(bindings, true_expr, false_expr) => self
735                .gen_when(bindings, true_expr, false_expr.as_deref(), ctx)
736                .map(|_| GeneratedExpressionResult::default()),
737            ExpressionKind::CompoundAssignment(target_location, operator_kind, source_expr) => self
738                .compound_assignment(target_location, operator_kind, source_expr, ctx)
739                .map(|_| GeneratedExpressionResult::default()),
740            ExpressionKind::IntrinsicCallEx(intrinsic_fn, arguments) => self
741                .gen_intrinsic_call_ex(intrinsic_fn, arguments, ctx)
742                .map(|_| GeneratedExpressionResult::default()),
743
744            ExpressionKind::Lambda(vec, x) => {
745                todo!()
746            }
747            // --------- Not high prio
748            ExpressionKind::CoerceOptionToBool(_) => todo!(),
749            ExpressionKind::FunctionValueCall(_, _, _) => todo!(),
750
751            // --------- TO BE REMOVED
752            ExpressionKind::IntrinsicFunctionAccess(_) => todo!(), // TODO: IntrinsicFunctionAccess should be reduced away in analyzer
753            ExpressionKind::ExternalFunctionAccess(_) => todo!(), // TODO: ExternalFunctionAccess should be reduced away in analyzer
754        };
755
756        self.debug_instructions();
757
758        result
759    }
760
761    fn gen_unary_operator(
762        &mut self,
763        unary_operator: &UnaryOperator,
764        ctx: &Context,
765    ) -> Result<(), Error> {
766        match &unary_operator.kind {
767            UnaryOperatorKind::Not => {}
768            UnaryOperatorKind::Negate => match (&unary_operator.left.ty) {
769                Type::Int => {
770                    let left_source = self.gen_expression_for_access(&unary_operator.left)?;
771                    self.state
772                        .builder
773                        .add_neg_i32(ctx.addr(), left_source.addr, "negate i32");
774                }
775
776                Type::Float => {
777                    let left_source = self.gen_expression_for_access(&unary_operator.left)?;
778                    self.state
779                        .builder
780                        .add_neg_f32(ctx.addr(), left_source.addr, "negate f32");
781                }
782                _ => todo!(),
783            },
784        }
785
786        Ok(())
787    }
788
789    fn gen_binary_operator(
790        &mut self,
791        binary_operator: &BinaryOperator,
792        ctx: &Context,
793    ) -> Result<GeneratedExpressionResult, Error> {
794        match (&binary_operator.left.ty, &binary_operator.right.ty) {
795            (Type::Int, Type::Int) => self.gen_binary_operator_i32(binary_operator, ctx),
796            (Type::Bool, Type::Bool) => self.gen_binary_operator_bool(binary_operator),
797            (Type::String, Type::String) => self.gen_binary_operator_string(binary_operator, ctx),
798            _ => todo!(),
799        }
800    }
801
802    fn gen_binary_operator_i32(
803        &mut self,
804        binary_operator: &BinaryOperator,
805        ctx: &Context,
806    ) -> Result<GeneratedExpressionResult, Error> {
807        let left_source = self.gen_expression_for_access(&binary_operator.left)?;
808        let right_source = self.gen_expression_for_access(&binary_operator.right)?;
809
810        match binary_operator.kind {
811            BinaryOperatorKind::Add => {
812                self.state.builder.add_add_i32(
813                    ctx.addr(),
814                    left_source.addr(),
815                    right_source.addr(),
816                    "i32 add",
817                );
818            }
819
820            BinaryOperatorKind::Subtract => todo!(),
821            BinaryOperatorKind::Multiply => {
822                self.state.builder.add_mul_i32(
823                    ctx.addr(),
824                    left_source.addr(),
825                    right_source.addr(),
826                    "i32 add",
827                );
828            }
829            BinaryOperatorKind::Divide => todo!(),
830            BinaryOperatorKind::Modulo => todo!(),
831            BinaryOperatorKind::LogicalOr => todo!(),
832            BinaryOperatorKind::LogicalAnd => todo!(),
833            BinaryOperatorKind::Equal => {
834                self.state
835                    .builder
836                    .add_eq_32(left_source.addr(), right_source.addr(), "i32 eq");
837            }
838            BinaryOperatorKind::NotEqual => todo!(),
839            BinaryOperatorKind::LessThan => {
840                self.state
841                    .builder
842                    .add_lt_i32(left_source.addr(), right_source.addr(), "i32 lt");
843            }
844            BinaryOperatorKind::LessEqual => todo!(),
845            BinaryOperatorKind::GreaterThan => {
846                self.state
847                    .builder
848                    .add_gt_i32(left_source.addr(), right_source.addr(), "i32 gt");
849            }
850            BinaryOperatorKind::GreaterEqual => todo!(),
851            BinaryOperatorKind::RangeExclusive => todo!(),
852        }
853
854        Ok(GeneratedExpressionResult {
855            has_set_bool_z_flag: true,
856        })
857    }
858
859    fn gen_binary_operator_string(
860        &mut self,
861        binary_operator: &BinaryOperator,
862        ctx: &Context,
863    ) -> Result<GeneratedExpressionResult, Error> {
864        let left_source = self.gen_expression_for_access(&binary_operator.left)?;
865        let right_source = self.gen_expression_for_access(&binary_operator.right)?;
866
867        match binary_operator.kind {
868            BinaryOperatorKind::Add => {
869                self.state.builder.add_string_append(
870                    ctx.addr(),
871                    left_source.addr(),
872                    right_source.addr(),
873                    "string add",
874                );
875            }
876
877            BinaryOperatorKind::Equal => todo!(),
878            BinaryOperatorKind::NotEqual => todo!(),
879            _ => panic!("illegal string operator"),
880        }
881
882        Ok(GeneratedExpressionResult {
883            has_set_bool_z_flag: false,
884        })
885    }
886
887    fn gen_binary_operator_bool(
888        &mut self,
889        binary_operator: &BinaryOperator,
890    ) -> Result<GeneratedExpressionResult, Error> {
891        match binary_operator.kind {
892            BinaryOperatorKind::LogicalOr => {
893                // this updates the z flag
894                self.gen_boolean_access_set_z_flag(&binary_operator.left);
895
896                let jump_after_patch = self
897                    .state
898                    .builder
899                    .add_jmp_if_equal_placeholder("skip rhs `or` expression");
900
901                // this updates the z flag
902                self.gen_boolean_access_set_z_flag(&binary_operator.right);
903
904                self.state.builder.patch_jump_here(jump_after_patch);
905            }
906            BinaryOperatorKind::LogicalAnd => {
907                // this updates the z flag
908                self.gen_boolean_access_set_z_flag(&binary_operator.left);
909
910                let jump_after_patch = self
911                    .state
912                    .builder
913                    .add_jmp_if_not_equal_placeholder("skip rhs `and` expression");
914
915                // this updates the z flag
916                self.gen_boolean_access_set_z_flag(&binary_operator.right);
917
918                self.state.builder.patch_jump_here(jump_after_patch);
919            }
920            _ => {
921                panic!("unknown operator")
922            }
923        }
924
925        Ok(GeneratedExpressionResult {
926            has_set_bool_z_flag: true,
927        })
928    }
929
930    fn gen_condition_context(
931        &mut self,
932        condition: &BooleanExpression,
933    ) -> Result<(Context, PatchPosition), Error> {
934        let condition_ctx = self.extra_frame_space_for_type(&Type::Bool);
935        self.gen_expression(&condition.expression, &condition_ctx)?;
936
937        let jump_on_false_condition = self
938            .state
939            .builder
940            .add_jmp_if_not_equal_placeholder("jump boolean condition false");
941
942        Ok((condition_ctx, jump_on_false_condition))
943    }
944
945    fn gen_boolean_access_set_z_flag(&mut self, condition: &Expression) -> Result<(), Error> {
946        let (frame_memory_region, gen_result) =
947            self.gen_expression_for_access_internal(condition)?;
948
949        if !gen_result.has_set_bool_z_flag {
950            self.state.builder.add_tst8(
951                frame_memory_region.addr,
952                "convert to boolean expression (update z flag)",
953            );
954        }
955
956        Ok(())
957    }
958
959    fn gen_boolean_expression(&mut self, condition: &BooleanExpression) -> Result<(), Error> {
960        self.gen_boolean_access_set_z_flag(&condition.expression)
961    }
962
963    fn gen_if(
964        &mut self,
965        condition: &BooleanExpression,
966        true_expr: &Expression,
967        maybe_false_expr: Option<&Expression>,
968        ctx: &Context,
969    ) -> Result<(), Error> {
970        let (_condition_ctx, jump_on_false_condition) = self.gen_condition_context(condition)?;
971
972        // True expression just takes over our target
973        self.gen_expression(true_expr, ctx)?;
974
975        if let Some(false_expr) = maybe_false_expr {
976            // we need to help the true expression to jump over false
977            let skip_false_if_true = self
978                .state
979                .builder
980                .add_jump_placeholder("condition is false skip");
981
982            // If the expression was false, it should continue here
983            self.state.builder.patch_jump_here(jump_on_false_condition);
984
985            // Else expression also can just take over our if target
986            self.gen_expression(false_expr, ctx)?;
987
988            self.state.builder.patch_jump_here(skip_false_if_true);
989        } else {
990            self.state.builder.patch_jump_here(jump_on_false_condition);
991        }
992
993        Ok(())
994    }
995
996    fn gen_while_loop(
997        &mut self,
998        condition: &BooleanExpression,
999        expression: &Expression,
1000        ctx: &Context,
1001    ) -> Result<(), Error> {
1002        // `while` loops are only for side effects, make sure that the target size is zero (Unit)
1003        assert_eq!(ctx.target_size().0, 0);
1004
1005        let ip_for_condition = self.state.builder.position();
1006
1007        let (_condition_ctx, jump_on_false_condition) = self.gen_condition_context(condition)?;
1008
1009        // Expression is only for side effects
1010        let mut unit_ctx = self.temp_space_for_type(&Type::Unit, "while body expression");
1011        self.gen_expression(expression, &mut unit_ctx)?;
1012
1013        // Always jump to the condition again to see if it is true
1014        self.state
1015            .builder
1016            .add_jmp(ip_for_condition, "jmp to while condition");
1017
1018        self.state.builder.patch_jump_here(jump_on_false_condition);
1019
1020        Ok(())
1021    }
1022
1023    fn gen_location_argument(
1024        &mut self,
1025        argument: &SingleLocationExpression,
1026        ctx: &Context,
1027        comment: &str,
1028    ) -> Result<(), Error> {
1029        let region = self.gen_lvalue_address(argument)?;
1030
1031        self.state
1032            .builder
1033            .add_mov(ctx.addr(), region.addr, region.size, comment);
1034
1035        Ok(())
1036    }
1037
1038    fn gen_variable_assignment(
1039        &mut self,
1040        variable: &VariableRef,
1041        mut_or_immutable_expression: &MutOrImmutableExpression,
1042        ctx: &Context,
1043    ) -> Result<(), Error> {
1044        let target_relative_frame_pointer = self
1045            .variable_offsets
1046            .get(&variable.unique_id_within_function)
1047            .unwrap_or_else(|| panic!("{}", variable.assigned_name));
1048
1049        let init_ctx =
1050            ctx.with_target(*target_relative_frame_pointer, "variable assignment target");
1051
1052        self.gen_mut_or_immute(mut_or_immutable_expression, &init_ctx)
1053    }
1054
1055    fn gen_assignment(
1056        &mut self,
1057        lhs: &SingleMutLocationExpression,
1058        rhs: &Expression,
1059    ) -> Result<(), Error> {
1060        let lhs_addr = self.gen_lvalue_address(&lhs.0)?;
1061        let access = self.gen_expression_for_access(rhs)?;
1062
1063        self.state
1064            .builder
1065            .add_mov(lhs_addr.addr, access.addr, access.size, "assignment");
1066
1067        Ok(())
1068    }
1069
1070    fn gen_variable_definition(
1071        &mut self,
1072        variable: &VariableRef,
1073        mut_or_immutable_expression: &MutOrImmutableExpression,
1074        ctx: &Context,
1075    ) -> Result<(), Error> {
1076        self.gen_variable_assignment(variable, mut_or_immutable_expression, ctx)
1077    }
1078
1079    fn gen_variable_reassignment(
1080        &mut self,
1081        variable: &VariableRef,
1082        mut_or_immutable_expression: &Box<MutOrImmutableExpression>,
1083        ctx: &Context,
1084    ) -> Result<(), Error> {
1085        self.gen_variable_assignment(variable, mut_or_immutable_expression, ctx)
1086    }
1087
1088    fn copy_back_mutable_arguments(
1089        &mut self,
1090        signature: &Signature,
1091        maybe_self: Option<FrameMemoryRegion>,
1092        arguments: &Vec<ArgumentExpressionOrLocation>,
1093    ) -> Result<(), Error> {
1094        let arguments_memory_region = self.infinite_above_frame_size();
1095        let mut arguments_allocator = ScopeAllocator::new(arguments_memory_region);
1096
1097        let _argument_addr = Self::reserve(&signature.return_type, &mut arguments_allocator);
1098
1099        let mut parameters = signature.parameters.clone();
1100        if let Some(found_self) = maybe_self {
1101            let source_region =
1102                Self::reserve(&parameters[0].resolved_type, &mut arguments_allocator);
1103            self.state.builder.add_mov(
1104                found_self.addr,
1105                source_region.addr,
1106                source_region.size,
1107                "copy back to <self>",
1108            );
1109            parameters.remove(0);
1110        }
1111        for (parameter, argument) in parameters.iter().zip(arguments) {
1112            let source_region = Self::reserve(&parameter.resolved_type, &mut arguments_allocator);
1113            if !parameter.is_mutable {
1114                continue;
1115            }
1116
1117            if let ArgumentExpressionOrLocation::Location(found_location) = argument {
1118                let argument_target = self.gen_lvalue_address(found_location)?;
1119                self.state.builder.add_mov(
1120                    argument_target.addr,
1121                    source_region.addr,
1122                    source_region.size,
1123                    &format!(
1124                        "copy back mutable argument {}",
1125                        found_location.starting_variable.assigned_name
1126                    ),
1127                );
1128            } else {
1129                panic!("internal error. argument is mut but not a location")
1130            }
1131        }
1132        Ok(())
1133    }
1134    fn gen_arguments(
1135        &mut self,
1136        signature: &Signature,
1137        self_region: Option<FrameMemoryRegion>,
1138        arguments: &Vec<ArgumentExpressionOrLocation>,
1139    ) -> Result<FrameMemoryRegion, Error> {
1140        self.argument_allocator.reset();
1141        // Layout return and arguments, must be continuous space
1142        let argument_addr = Self::reserve(&signature.return_type, &mut self.argument_allocator);
1143        assert_eq!(argument_addr.addr.0, self.frame_size.0);
1144
1145        let mut argument_targets = Vec::new();
1146        let mut argument_comments = Vec::new();
1147
1148        // Layout arguments, must be continuous space
1149        for (index, type_for_parameter) in signature.parameters.iter().enumerate() {
1150            let argument_target = Self::reserve(
1151                &type_for_parameter.resolved_type,
1152                &mut self.argument_allocator,
1153            );
1154            let arg_ctx = Context::new(argument_target);
1155            argument_targets.push(arg_ctx);
1156            argument_comments.push(format!("argument {}", type_for_parameter.name));
1157        }
1158
1159        if let Some(push_self) = self_region {
1160            self.state.builder.add_mov(
1161                argument_targets[0].addr(),
1162                push_self.addr,
1163                push_self.size,
1164                "<self>",
1165            );
1166            argument_targets.remove(0);
1167        }
1168
1169        for ((argument_target_ctx, argument_expr_or_loc), argument_comment) in argument_targets
1170            .iter()
1171            .zip(arguments)
1172            .zip(argument_comments)
1173        {
1174            let debug_addr = argument_target_ctx.target().addr();
1175            self.gen_argument(
1176                argument_expr_or_loc,
1177                &argument_target_ctx,
1178                &argument_comment,
1179            )?;
1180        }
1181
1182        let memory_size = argument_targets
1183            .last()
1184            .map_or(MemorySize(0), |last_target| {
1185                MemorySize(
1186                    last_target.addr().add(last_target.target_size()).0
1187                        - argument_targets[0].addr().0,
1188                )
1189            });
1190
1191        let start_addr = argument_targets
1192            .first()
1193            .map_or(FrameMemoryAddress(0), |first| first.addr());
1194
1195        Ok(FrameMemoryRegion {
1196            addr: start_addr,
1197            size: memory_size,
1198        })
1199    }
1200
1201    #[allow(clippy::too_many_lines)]
1202    fn gen_postfix_chain(
1203        &mut self,
1204        start_expression: &Expression,
1205        chain: &[Postfix],
1206        ctx: &Context,
1207    ) -> Result<(), Error> {
1208        if let ExpressionKind::InternalFunctionAccess(internal_fn) = &start_expression.kind {
1209            if chain.len() == 1 {
1210                if let PostfixKind::FunctionCall(args) = &chain[0].kind {
1211                    if let Some(intrinsic_fn) = single_intrinsic_fn(&internal_fn.body) {
1212                        self.gen_single_intrinsic_call(intrinsic_fn, None, args, ctx)?;
1213                    } else {
1214                        self.gen_arguments(&internal_fn.signature, None, args)?;
1215                        self.state
1216                            .add_call(internal_fn, &format!("frame size: {}", self.frame_size)); // will be fixed up later
1217                        let (return_size, _alignment) =
1218                            type_size_and_alignment(&internal_fn.signature.return_type);
1219                        if return_size.0 != 0 {
1220                            self.state.builder.add_mov(
1221                                ctx.addr(),
1222                                self.infinite_above_frame_size().addr,
1223                                return_size,
1224                                "copy the ret value to destination",
1225                            );
1226                        }
1227                        self.copy_back_mutable_arguments(&internal_fn.signature, None, args)?;
1228                    }
1229
1230                    return Ok(());
1231                }
1232            }
1233        }
1234
1235        if let ExpressionKind::ExternalFunctionAccess(external_fn) = &start_expression.kind {
1236            if chain.len() == 1 {
1237                if let PostfixKind::FunctionCall(args) = &chain[0].kind {
1238                    let total_region = self.gen_arguments(&external_fn.signature, None, args)?;
1239                    self.state.builder.add_host_call(
1240                        external_fn.id as u16,
1241                        total_region.size,
1242                        &format!("call external '{}'", external_fn.assigned_name),
1243                    );
1244                    let (return_size, _alignment) =
1245                        type_size_and_alignment(&external_fn.signature.return_type);
1246                    if return_size.0 != 0 {
1247                        self.state.builder.add_mov(
1248                            ctx.addr(),
1249                            self.infinite_above_frame_size().addr,
1250                            return_size,
1251                            "copy the ret value to destination",
1252                        );
1253                    }
1254
1255                    return Ok(());
1256                }
1257            }
1258        }
1259
1260        let mut start_source = self.gen_expression_for_access(start_expression)?;
1261
1262        for element in chain {
1263            match &element.kind {
1264                PostfixKind::StructField(anonymous_struct, field_index) => {
1265                    let (memory_offset, memory_size, _max_alignment) =
1266                        Self::get_struct_field_offset(
1267                            &anonymous_struct.field_name_sorted_fields,
1268                            *field_index,
1269                        );
1270                    start_source = FrameMemoryRegion::new(
1271                        start_source.addr.advance(memory_offset),
1272                        memory_size,
1273                    );
1274                }
1275                PostfixKind::MemberCall(function_to_call, arguments) => {
1276                    match &**function_to_call {
1277                        Function::Internal(internal_fn) => {
1278                            if let Some(intrinsic_fn) = single_intrinsic_fn(&internal_fn.body) {
1279                                self.gen_single_intrinsic_call(
1280                                    intrinsic_fn,
1281                                    Some(start_source),
1282                                    arguments,
1283                                    ctx,
1284                                )?;
1285                            } else {
1286                                self.gen_arguments(
1287                                    &internal_fn.signature,
1288                                    Some(start_source),
1289                                    arguments,
1290                                )?;
1291                                self.state.add_call(
1292                                    internal_fn,
1293                                    &format!("frame size: {}", self.frame_size),
1294                                ); // will be fixed up later
1295
1296                                let (return_size, _alignment) =
1297                                    type_size_and_alignment(&internal_fn.signature.return_type);
1298                                if return_size.0 != 0 {
1299                                    self.state.builder.add_mov(
1300                                        ctx.addr(),
1301                                        self.infinite_above_frame_size().addr,
1302                                        return_size,
1303                                        "copy the return value to destination",
1304                                    );
1305                                }
1306
1307                                self.copy_back_mutable_arguments(
1308                                    &internal_fn.signature,
1309                                    Some(start_source),
1310                                    arguments,
1311                                )?;
1312                            }
1313                        }
1314                        Function::External(external_fn) => {
1315                            //self.state.builder.add_host_call(external_fn.id);
1316                        }
1317                    }
1318                }
1319                PostfixKind::FunctionCall(arguments) => {
1320                    //self.gen_arguments(arguments);
1321                    //self.state.add_call(start_expression)
1322                }
1323                PostfixKind::OptionUnwrap => todo!(),
1324                PostfixKind::NoneCoalesce(_) => todo!(),
1325            }
1326        }
1327
1328        Ok(())
1329    }
1330
1331    fn gen_tuple(&mut self, expressions: &[Expression], ctx: &Context) -> Result<(), Error> {
1332        let mut scope = ScopeAllocator::new(ctx.target());
1333
1334        for expr in expressions {
1335            let (memory_size, alignment) = type_size_and_alignment(&expr.ty);
1336            let start_addr = scope.allocate(memory_size, alignment);
1337            let element_region = FrameMemoryRegion::new(start_addr, memory_size);
1338            let element_ctx = Context::new(element_region);
1339            self.gen_expression(expr, &element_ctx)?;
1340        }
1341
1342        Ok(())
1343    }
1344
1345    fn get_struct_field_offset(
1346        fields: &SeqMap<String, StructTypeField>,
1347        index_to_find: usize,
1348    ) -> (MemoryOffset, MemorySize, MemoryAlignment) {
1349        let mut offset = 0;
1350
1351        for (index, (_name, field)) in fields.iter().enumerate() {
1352            let (struct_field_size, struct_field_align) =
1353                type_size_and_alignment(&field.field_type);
1354            if index == index_to_find {
1355                return (MemoryOffset(offset), struct_field_size, struct_field_align);
1356            }
1357
1358            offset += struct_field_size.0;
1359        }
1360
1361        panic!("field not found");
1362    }
1363
1364    fn gen_anonymous_struct(
1365        &mut self,
1366        anon_struct_type: &AnonymousStructType,
1367        source_order_expressions: &Vec<(usize, Expression)>,
1368        base_context: &Context,
1369    ) -> Result<(), Error> {
1370        for (field_index, expression) in source_order_expressions {
1371            let (field_memory_offset, field_size, _field_alignment) = Self::get_struct_field_offset(
1372                &anon_struct_type.field_name_sorted_fields,
1373                *field_index,
1374            );
1375            let field_ctx = base_context.with_offset(field_memory_offset, field_size);
1376            self.gen_expression(expression, &field_ctx)?;
1377        }
1378
1379        Ok(())
1380    }
1381
1382    fn gen_literal(&mut self, literal: &Literal, ctx: &Context) -> Result<(), Error> {
1383        match literal {
1384            Literal::IntLiteral(int) => {
1385                self.state.builder.add_ld32(ctx.addr(), *int, "int literal");
1386            }
1387            Literal::FloatLiteral(fixed_point) => {
1388                self.state
1389                    .builder
1390                    .add_ld32(ctx.addr(), fixed_point.inner(), "float literal");
1391            }
1392            Literal::NoneLiteral => {
1393                self.state.builder.add_ld8(ctx.addr(), 0, "none literal");
1394            }
1395            Literal::BoolLiteral(truthy) => {
1396                self.state
1397                    .builder
1398                    .add_ld8(ctx.addr(), u8::from(*truthy), "bool literal");
1399            }
1400
1401            Literal::EnumVariantLiteral(enum_type, a, b) => {
1402                self.state.builder.add_ld8(
1403                    ctx.addr(),
1404                    a.common().container_index,
1405                    &format!("enum variant {} tag", a.common().assigned_name),
1406                );
1407
1408                let starting_offset = MemoryOffset(1);
1409
1410                let (data_size, data_alignment) = match a {
1411                    EnumVariantType::Struct(enum_variant_struct) => {
1412                        layout_struct(&enum_variant_struct.anon_struct)
1413                    }
1414                    EnumVariantType::Tuple(tuple_type) => layout_tuple(&tuple_type.fields_in_order),
1415                    EnumVariantType::Nothing(_) => (MemorySize(0), MemoryAlignment::U8),
1416                };
1417
1418                let skip_octets: usize = data_alignment.into();
1419                let skip = MemorySize(skip_octets as u16);
1420                let inner_addr = ctx.addr().add(skip);
1421                let region = FrameMemoryRegion::new(inner_addr, data_size);
1422                let inner_ctx = Context::new(region);
1423
1424                //layout_union(a)
1425                match b {
1426                    EnumLiteralData::Nothing => {}
1427                    EnumLiteralData::Tuple(expressions) => {
1428                        self.gen_tuple(expressions, &inner_ctx)?;
1429                    }
1430                    EnumLiteralData::Struct(sorted_expressions) => {
1431                        if let EnumVariantType::Struct(variant_struct_type) = a {
1432                            self.gen_anonymous_struct(
1433                                &variant_struct_type.anon_struct,
1434                                sorted_expressions,
1435                                &inner_ctx,
1436                            )?;
1437                        }
1438                    }
1439                }
1440            }
1441            Literal::TupleLiteral(_tuple_type, expressions) => self.gen_tuple(expressions, ctx)?,
1442            Literal::StringLiteral(str) => {
1443                self.gen_string_literal(str, ctx);
1444            }
1445            Literal::Slice(ty, expressions) => {
1446                //self.gen_slice_literal(ty, expressions, ctx)
1447                todo!()
1448            }
1449            Literal::SlicePair(ty, expression_pairs) => {
1450                todo!()
1451            }
1452        }
1453
1454        Ok(())
1455    }
1456
1457    fn gen_string_literal(&mut self, string: &str, ctx: &Context) {
1458        let string_bytes = string.as_bytes();
1459        let string_byte_count = string_bytes.len();
1460
1461        let data_ptr = self
1462            .state
1463            .constants
1464            .allocate(string_bytes, MemoryAlignment::U8);
1465
1466        let mem_size = MemorySize(string_byte_count as u16);
1467
1468        self.state.builder.add_string_from_constant_slice(
1469            ctx.addr(),
1470            data_ptr,
1471            mem_size,
1472            "create string",
1473        );
1474        // self.gen_vec_immediate(data_ptr, mem_size, mem_size, "string", ctx);
1475    }
1476
1477    /*
1478    fn gen_vec_immediate(
1479        &mut self,
1480        data_ptr: MemoryAddress,
1481        len: MemorySize,
1482        capacity: MemorySize,
1483        comment_prefix: &str,
1484        ctx: &Context,
1485    ) {
1486        self.state
1487            .builder
1488            .add_ld_u16(ctx.addr(), len.0, &format!("{} len", comment_prefix));
1489
1490        self.state.builder.add_ld_u16(
1491            ctx.addr().add(MemorySize(2)),
1492            capacity.0,
1493            &format!("{} capacity", comment_prefix),
1494        );
1495
1496        self.state.builder.add_ld_u16(
1497            ctx.addr().add(MemorySize(4)),
1498            data_ptr.0,
1499            &format!("{} ptr", comment_prefix),
1500        );
1501    }
1502
1503
1504     */
1505    fn gen_option_expression(
1506        &mut self,
1507        maybe_option: Option<&Expression>,
1508        ctx: &Context,
1509    ) -> Result<(), Error> {
1510        if let Some(found_value) = maybe_option {
1511            self.state.builder.add_ld8(ctx.addr(), 1, "option Some tag"); // 1 signals `Some`
1512            let (inner_size, inner_alignment) = type_size_and_alignment(&found_value.ty);
1513            let one_offset_ctx = ctx.with_offset(inner_alignment.into(), inner_size);
1514
1515            self.gen_expression(found_value, &one_offset_ctx)?; // Fills in more of the union
1516        } else {
1517            self.state.builder.add_ld8(ctx.addr(), 0, "option None tag"); // 0 signals `None`
1518            // No real need to clear the rest of the memory
1519        }
1520
1521        Ok(())
1522    }
1523
1524    fn gen_for_loop_vec(
1525        &mut self,
1526        for_pattern: &ForPattern,
1527        collection_expr: &MutOrImmutableExpression,
1528    ) -> Result<(InstructionPosition, PatchPosition), Error> {
1529        let collection_region = self.gen_for_access_or_location(collection_expr)?;
1530
1531        let temp_iterator_region = self
1532            .temp_allocator
1533            .allocate(MemorySize(VEC_ITERATOR_SIZE), VEC_ITERATOR_ALIGNMENT);
1534        self.state.builder.add_vec_iter_init(
1535            temp_iterator_region,
1536            FrameMemoryAddressIndirectPointer(collection_region.addr),
1537            "initialize vec iterator",
1538        );
1539
1540        let loop_ip = self.state.builder.position();
1541
1542        let placeholder_position = match for_pattern {
1543            ForPattern::Single(variable) => {
1544                let target_variable = self
1545                    .variable_offsets
1546                    .get(&variable.unique_id_within_function)
1547                    .unwrap();
1548                self.state.builder.add_vec_iter_next_placeholder(
1549                    temp_iterator_region,
1550                    target_variable.addr,
1551                    "move to next or jump over",
1552                )
1553            }
1554            ForPattern::Pair(variable_a, variable_b) => {
1555                let target_variable_a = self
1556                    .variable_offsets
1557                    .get(&variable_a.unique_id_within_function)
1558                    .unwrap();
1559                let target_variable_b = self
1560                    .variable_offsets
1561                    .get(&variable_b.unique_id_within_function)
1562                    .unwrap();
1563                self.state.builder.add_vec_iter_next_pair_placeholder(
1564                    temp_iterator_region,
1565                    target_variable_a.addr,
1566                    target_variable_b.addr,
1567                    "move to next or jump over",
1568                )
1569            }
1570        };
1571
1572        Ok((loop_ip, placeholder_position))
1573    }
1574
1575    fn gen_for_loop_map(
1576        &mut self,
1577        for_pattern: &ForPattern,
1578    ) -> Result<(InstructionPosition, PatchPosition), Error> {
1579        self.state.builder.add_map_iter_init(
1580            FrameMemoryAddress(0x80),
1581            FrameMemoryAddressIndirectPointer(FrameMemoryAddress(0xffff)),
1582            "initialize map iterator",
1583        );
1584
1585        let jump_ip = self.state.builder.position();
1586
1587        match for_pattern {
1588            ForPattern::Single(_) => {
1589                self.state.builder.add_map_iter_next(
1590                    FrameMemoryAddress(0x80),
1591                    FrameMemoryAddress(0x16),
1592                    InstructionPosition(256),
1593                    "move to next or jump over",
1594                );
1595            }
1596            ForPattern::Pair(_, _) => {
1597                self.state.builder.add_map_iter_next_pair(
1598                    FrameMemoryAddress(0x80),
1599                    FrameMemoryAddress(0x16),
1600                    FrameMemoryAddress(0x16),
1601                    InstructionPosition(256),
1602                    "move to next or jump over",
1603                );
1604            }
1605        }
1606
1607        Ok((jump_ip, PatchPosition(InstructionPosition(0))))
1608    }
1609
1610    fn gen_for_loop(
1611        &mut self,
1612        for_pattern: &ForPattern,
1613        iterable: &Iterable,
1614        closure: &Box<Expression>,
1615    ) -> Result<(), Error> {
1616        // Add check if the collection is empty, to skip everything
1617
1618        // get some kind of iteration pointer
1619
1620        // check if it has reached its end
1621
1622        let collection_type = &iterable.resolved_expression.expression_or_location.ty();
1623        let (jump_ip, placeholder_position) = match collection_type {
1624            Type::String => {
1625                todo!();
1626            }
1627            Type::NamedStruct(_vec) => {
1628                if let Some(found_info) = is_vec(collection_type) {
1629                    self.gen_for_loop_vec(for_pattern, &iterable.resolved_expression)?
1630                } else if let Some(found_info) = is_map(collection_type) {
1631                    self.gen_for_loop_map(for_pattern)?
1632                } else {
1633                    return Err(self.create_err(
1634                        ErrorKind::NotAnIterableCollection,
1635                        iterable.resolved_expression.node(),
1636                    ));
1637                }
1638            }
1639            _ => {
1640                return Err(self.create_err(
1641                    ErrorKind::IllegalCollection,
1642                    iterable.resolved_expression.node(),
1643                ));
1644            }
1645        };
1646
1647        match for_pattern {
1648            ForPattern::Single(value_variable) => {}
1649            ForPattern::Pair(key_variable, value_variable) => {}
1650        }
1651
1652        let unit_expr = self.temp_space_for_type(&Type::Unit, "for loop body");
1653        self.gen_expression(closure, &unit_expr)?;
1654
1655        self.state
1656            .builder
1657            .add_jmp(jump_ip, "jump to next iteration");
1658        // advance iterator pointer
1659        // jump to check if iterator pointer has reached its end
1660        self.state.builder.patch_jump_here(placeholder_position);
1661
1662        Ok(())
1663    }
1664
1665    fn gen_for_loop_for_vec(
1666        &mut self,
1667        element_type: &Type,
1668        vector_expr: Expression,
1669        ctx: &mut Context,
1670    ) -> Result<GeneratedExpressionResult, Error> {
1671        // get the vector that is referenced
1672        let vector_ctx = self.temp_space_for_type(&vector_expr.ty, "vector space");
1673        self.gen_expression(&vector_expr, &vector_ctx)
1674
1675        /*
1676        let value_var_addr = match for_pattern {
1677            ForPattern::Single(value_variable) => self
1678                .variable_offsets
1679                .get(&value_variable.unique_id_within_function)
1680                .expect("Variable not found"),
1681            ForPattern::Pair(_, _) => {
1682                panic!("Cannot use key-value pattern with vectors");
1683            }
1684        };
1685
1686         */
1687
1688        /*
1689        let element_size = type_size(element_type);
1690               // Temporary for the counter
1691               let counter_addr = ctx.allocate_temp(MemorySize(2)); // u16 counter
1692               self.state
1693                   .builder
1694                   .add_ld_u16(counter_addr, 0, "temporary counter");
1695
1696               let loop_start_pos = self.state.builder.position();
1697
1698               // vector length
1699               let length_addr = ctx.allocate_temp(MemorySize(2));
1700               self.state.builder.add_mov(
1701                   length_addr,
1702                   vector_ctx.addr().add(MemorySize(VECTOR_LENGTH_OFFSET)),
1703                   MemorySize(2),
1704                   "vector length",
1705               );
1706
1707               // Compare counter < length
1708               let compare_result_addr = ctx.allocate_temp(MemorySize(1)); // boolean result
1709               self.state.builder.add_lt_u16(
1710                   compare_result_addr,
1711                   counter_addr,
1712                   length_addr,
1713                   "counter < length",
1714               );
1715
1716               // Exit loop if counter >= length
1717               let exit_jump = self
1718                   .state
1719                   .builder
1720                   .add_conditional_jump_placeholder(compare_result_addr, "counter >= length exit");
1721
1722               let data_ptr_addr = ctx.allocate_temp(MemorySize(2));
1723               self.state.builder.add_mov(
1724                   data_ptr_addr,
1725                   vector_ctx.addr().add(MemorySize(VECTOR_DATA_PTR_OFFSET)),
1726                   MemorySize(PTR_SIZE),
1727                   "copy vector data ptr",
1728               );
1729
1730
1731        */
1732        /*
1733        let offset_addr = ctx.allocate_temp(2);
1734        self.state.builder.add_mul_u16(
1735            offset_addr,
1736            counter_addr,
1737            element_size
1738        );
1739
1740        self.state.builder.add_ld_indirect(
1741            *value_var_addr,     // Destination: loop variable
1742            data_ptr_addr,       // Base: vector's data pointer
1743            offset_addr,         // Offset: counter * element_size
1744            element_size         // Size to copy
1745        );
1746
1747        let mut body_ctx = ctx.temp_space_for_type(&Type::Unit);
1748        self.gen_expression(body, &mut body_ctx);
1749
1750        self.state.builder.add_inc_u16(counter_addr);
1751
1752        self.state.builder.add_jmp_to_position(loop_start_pos);
1753
1754        let end_pos = self.state.builder.current_position();
1755        self.state.builder.patch_jump(exit_jump, end_pos);
1756
1757         */
1758    }
1759
1760    fn gen_block(&mut self, expressions: &[Expression], ctx: &Context) -> Result<(), Error> {
1761        if let Some((last, others)) = expressions.split_last() {
1762            for expr in others {
1763                let temp_context = self.temp_space_for_type(&Type::Unit, "block target");
1764                self.gen_expression(expr, &temp_context)?;
1765            }
1766            self.gen_expression(last, ctx)?;
1767        }
1768
1769        Ok(())
1770    }
1771
1772    fn get_variable_region(&self, variable: &VariableRef) -> (FrameMemoryRegion, MemoryAlignment) {
1773        let frame_address = self
1774            .variable_offsets
1775            .get(&variable.unique_id_within_function)
1776            .unwrap();
1777        let (_size, align) = type_size_and_alignment(&variable.resolved_type);
1778
1779        (*frame_address, align)
1780    }
1781
1782    fn gen_variable_access(&mut self, variable: &VariableRef, ctx: &Context) -> Result<(), Error> {
1783        let (region, alignment) = self.get_variable_region(variable);
1784        self.state.builder.add_mov(
1785            ctx.addr(),
1786            region.addr,
1787            region.size,
1788            &format!(
1789                "variable access '{}' ({})",
1790                variable.assigned_name,
1791                ctx.comment()
1792            ),
1793        );
1794
1795        Ok(())
1796    }
1797
1798    fn referenced_or_not_type(ty: &Type) -> Type {
1799        if let Type::MutableReference(inner_type) = ty {
1800            *inner_type.clone()
1801        } else {
1802            ty.clone()
1803        }
1804    }
1805
1806    fn compound_assignment(
1807        &mut self,
1808        target_location: &SingleMutLocationExpression,
1809        op: &CompoundOperatorKind,
1810        source: &Expression,
1811        ctx: &Context,
1812    ) -> Result<(), Error> {
1813        let target_location = self.gen_lvalue_address(&target_location.0)?;
1814
1815        let source_info = self.gen_expression_for_access(source)?;
1816
1817        let type_to_consider = Self::referenced_or_not_type(&source.ty);
1818
1819        match &type_to_consider {
1820            Type::Int => {
1821                self.gen_compound_assignment_i32(&target_location, op, &source_info);
1822            }
1823            Type::Float => {
1824                self.gen_compound_assignment_f32(&target_location, op, &source_info);
1825            }
1826            Type::String => todo!(),
1827            _ => return Err(self.create_err(ErrorKind::IllegalCompoundAssignment, &source.node)),
1828        }
1829
1830        Ok(())
1831    }
1832
1833    fn gen_compound_assignment_i32(
1834        &mut self,
1835        target: &FrameMemoryRegion,
1836        op: &CompoundOperatorKind,
1837        source_ctx: &FrameMemoryRegion,
1838    ) {
1839        match op {
1840            CompoundOperatorKind::Add => {
1841                self.state.builder.add_add_i32(
1842                    target.addr(),
1843                    target.addr(),
1844                    source_ctx.addr(),
1845                    "+=  (i32)",
1846                );
1847            }
1848            CompoundOperatorKind::Sub => todo!(),
1849            CompoundOperatorKind::Mul => todo!(),
1850            CompoundOperatorKind::Div => todo!(),
1851            CompoundOperatorKind::Modulo => todo!(),
1852        }
1853    }
1854
1855    fn gen_compound_assignment_f32(
1856        &mut self,
1857        target: &FrameMemoryRegion,
1858        op: &CompoundOperatorKind,
1859        source_ctx: &FrameMemoryRegion,
1860    ) {
1861        match op {
1862            CompoundOperatorKind::Add => {
1863                self.state.builder.add_add_f32(
1864                    target.addr(),
1865                    target.addr(),
1866                    source_ctx.addr(),
1867                    "+=  (f32)",
1868                );
1869            }
1870            CompoundOperatorKind::Sub => todo!(),
1871            CompoundOperatorKind::Mul => todo!(),
1872            CompoundOperatorKind::Div => todo!(),
1873            CompoundOperatorKind::Modulo => todo!(),
1874        }
1875    }
1876
1877    fn internal_function_access(
1878        &mut self,
1879        internal: &InternalFunctionDefinitionRef,
1880        ctx: &Context,
1881    ) -> Result<(), Error> {
1882        self.state.builder.add_ld_u16(
1883            ctx.addr(),
1884            internal.program_unique_id,
1885            &format!("function access '{}'", internal.assigned_name),
1886        );
1887        Ok(())
1888    }
1889
1890    fn infinite_above_frame_size(&self) -> FrameMemoryRegion {
1891        FrameMemoryRegion::new(FrameMemoryAddress(self.frame_size.0), MemorySize(1024))
1892    }
1893
1894    fn gen_struct_literal(
1895        &mut self,
1896        struct_literal: &StructInstantiation,
1897        ctx: &Context,
1898    ) -> Result<(), Error> {
1899        self.gen_struct_literal_helper(
1900            &struct_literal.struct_type_ref.anon_struct_type,
1901            &struct_literal.source_order_expressions,
1902            ctx,
1903        )
1904    }
1905
1906    fn gen_anonymous_struct_literal(
1907        &mut self,
1908        anon_struct_literal: &AnonymousStructLiteral,
1909        ctx: &Context,
1910    ) -> Result<(), Error> {
1911        self.gen_struct_literal_helper(
1912            &anon_struct_literal.anonymous_struct_type,
1913            &anon_struct_literal.source_order_expressions,
1914            ctx,
1915        )
1916    }
1917
1918    fn gen_struct_literal_helper(
1919        &mut self,
1920        struct_type_ref: &AnonymousStructType,
1921        source_order_expressions: &Vec<(usize, Expression)>,
1922        ctx: &Context,
1923    ) -> Result<(), Error> {
1924        let struct_type = Type::AnonymousStruct(struct_type_ref.clone());
1925        let (whole_struct_size, whole_struct_alignment) = type_size_and_alignment(&struct_type);
1926        if ctx.target_size().0 != whole_struct_size.0 {
1927            info!("problem");
1928        }
1929        assert_eq!(ctx.target_size().0, whole_struct_size.0);
1930
1931        for (field_index, expression) in source_order_expressions {
1932            let (field_offset, field_size, field_alignment) =
1933                struct_field_offset(*field_index, struct_type_ref);
1934            //info!(?field_offset, ?field_index, "field offset");
1935            let new_address = ctx.addr().advance(field_offset);
1936            let field_ctx = Context::new(FrameMemoryRegion::new(new_address, field_size));
1937            self.gen_expression(expression, &field_ctx)?;
1938        }
1939
1940        Ok(())
1941    }
1942
1943    fn gen_slice_literal(
1944        &mut self,
1945        ty: &Type,
1946        expressions: &Vec<Expression>,
1947    ) -> Result<FrameMemoryRegion, Error> {
1948        let (element_size, element_alignment) = type_size_and_alignment(ty);
1949        let element_count = expressions.len() as u16;
1950        let total_slice_size = MemorySize(element_size.0 * element_count);
1951
1952        let start_frame_address_to_transfer = self
1953            .temp_allocator
1954            .allocate(total_slice_size, element_alignment);
1955        for (index, expr) in expressions.iter().enumerate() {
1956            let memory_offset = MemoryOffset((index as u16) * element_size.0);
1957            let region = FrameMemoryRegion::new(
1958                start_frame_address_to_transfer.advance(memory_offset),
1959                element_size,
1960            );
1961            let element_ctx = Context::new(region);
1962            self.gen_expression(expr, &element_ctx)?;
1963        }
1964
1965        Ok(FrameMemoryRegion::new(
1966            start_frame_address_to_transfer,
1967            total_slice_size,
1968        ))
1969    }
1970
1971    fn gen_slice_pair_literal(
1972        &mut self,
1973        slice_type: &Type,
1974        expressions: &[(Expression, Expression)],
1975    ) -> SlicePairInfo {
1976        let Type::SlicePair(key_type, value_type) = slice_type else {
1977            panic!("should have been slice pair type")
1978        };
1979
1980        let constructed_tuple = Type::Tuple(vec![*key_type.clone(), *value_type.clone()]);
1981
1982        let (key_size, key_alignment) = type_size_and_alignment(key_type);
1983        let (value_size, value_alignment) = type_size_and_alignment(value_type);
1984        let (element_size, tuple_alignment) = type_size_and_alignment(&constructed_tuple);
1985        let element_count = expressions.len() as u16;
1986        let total_slice_size = MemorySize(element_size.0 * element_count);
1987
1988        let start_frame_address_to_transfer = self
1989            .temp_allocator
1990            .allocate(total_slice_size, tuple_alignment);
1991
1992        for (index, (key_expr, value_expr)) in expressions.iter().enumerate() {
1993            let memory_offset = MemoryOffset((index as u16) * element_size.0);
1994            let key_region = FrameMemoryRegion::new(
1995                start_frame_address_to_transfer.advance(memory_offset),
1996                element_size,
1997            );
1998            let key_ctx = Context::new(key_region);
1999            self.gen_expression(key_expr, &key_ctx);
2000
2001            let value_region = FrameMemoryRegion::new(
2002                start_frame_address_to_transfer.advance(memory_offset.add(key_size, key_alignment)),
2003                value_size,
2004            );
2005            let value_ctx = Context::new(value_region);
2006            self.gen_expression(value_expr, &value_ctx);
2007        }
2008
2009        SlicePairInfo {
2010            addr: TempFrameMemoryAddress(start_frame_address_to_transfer),
2011            key_size,
2012            value_size,
2013            element_count: CountU16(element_count),
2014            element_size,
2015        }
2016    }
2017
2018    fn gen_slice_helper(
2019        &mut self,
2020        start_temp_frame_address_to_transfer: FrameMemoryAddress,
2021        element_count: u16,
2022        element_size: MemorySize,
2023        ctx: &Context,
2024    ) {
2025        let total_slice_size = MemorySize(element_size.0 * element_count);
2026        let vec_len_addr = ctx.addr().advance(MemoryOffset(0));
2027        self.state
2028            .builder
2029            .add_ld_u16(vec_len_addr, element_count, "slice len");
2030
2031        let vec_capacity_addr = ctx.addr().advance(MemoryOffset(2));
2032        self.state
2033            .builder
2034            .add_ld_u16(vec_capacity_addr, element_count, "slice capacity");
2035
2036        let vec_element_size_addr = ctx.addr().advance(MemoryOffset(4));
2037        self.state
2038            .builder
2039            .add_ld_u16(vec_element_size_addr, element_size.0, "slice element size");
2040
2041        /*
2042        let allocated_vec_address = ctx.addr().advance(MemoryOffset(6));
2043        self.state
2044        .builder
2045        add_alloc(allocated_vec_address, total_slice_size, "slice literal");
2046
2047        self.state.builder.add_stx(
2048            allocated_vec_address,
2049            MemoryOffset(0),
2050            start_temp_frame_address_to_transfer,
2051            total_slice_size,
2052            "copy from slice continuous temporary frame memory to allocated vec ptr heap area",
2053        );
2054
2055         */
2056    }
2057
2058    fn gen_intrinsic_call_ex(
2059        &mut self,
2060        intrinsic_fn: &IntrinsicFunction,
2061        arguments: &Vec<ArgumentExpressionOrLocation>,
2062        ctx: &Context,
2063    ) -> Result<(), Error> {
2064        //        info!(?intrinsic_fn, "generating intrinsic call");
2065
2066        match intrinsic_fn {
2067            // Fixed
2068            IntrinsicFunction::FloatRound => todo!(),
2069            IntrinsicFunction::FloatFloor => todo!(),
2070            IntrinsicFunction::FloatSqrt => todo!(),
2071            IntrinsicFunction::FloatSign => todo!(),
2072            IntrinsicFunction::FloatAbs => todo!(),
2073            IntrinsicFunction::FloatRnd => todo!(),
2074            IntrinsicFunction::FloatCos => todo!(),
2075            IntrinsicFunction::FloatSin => todo!(),
2076            IntrinsicFunction::FloatAcos => todo!(),
2077            IntrinsicFunction::FloatAsin => todo!(),
2078            IntrinsicFunction::FloatAtan2 => todo!(),
2079            IntrinsicFunction::FloatMin => todo!(),
2080            IntrinsicFunction::FloatMax => todo!(),
2081            IntrinsicFunction::FloatClamp => todo!(),
2082
2083            // i32
2084            IntrinsicFunction::IntAbs => todo!(),
2085            IntrinsicFunction::IntRnd => todo!(),
2086            IntrinsicFunction::IntMax => todo!(),
2087            IntrinsicFunction::IntMin => todo!(),
2088            IntrinsicFunction::IntClamp => todo!(),
2089            IntrinsicFunction::IntToFloat => todo!(),
2090
2091            // String
2092            IntrinsicFunction::StringLen => todo!(),
2093
2094            // Vector
2095            IntrinsicFunction::VecFromSlice => self.gen_intrinsic_vec_from_slice(arguments, ctx),
2096            IntrinsicFunction::VecPush => todo!(),
2097            IntrinsicFunction::VecPop => todo!(),
2098            IntrinsicFunction::VecFor => todo!(),
2099            IntrinsicFunction::VecRemoveIndex => todo!(),
2100            IntrinsicFunction::VecClear => todo!(),
2101            IntrinsicFunction::VecCreate => {
2102                self.gen_intrinsic_vec_create(arguments);
2103                Ok(())
2104            }
2105            IntrinsicFunction::VecSubscript => todo!(),
2106            IntrinsicFunction::VecSubscriptMut => todo!(),
2107            IntrinsicFunction::VecSubscriptRange => todo!(),
2108            IntrinsicFunction::VecIter => todo!(), // intentionally disregard, since it is never called
2109            IntrinsicFunction::VecIterMut => todo!(), // intentionally disregard, since it is never called
2110            IntrinsicFunction::VecLen => todo!(),
2111            IntrinsicFunction::VecIsEmpty => todo!(),
2112            IntrinsicFunction::VecSelfPush => todo!(),
2113            IntrinsicFunction::VecSelfExtend => todo!(),
2114
2115            // Map
2116            IntrinsicFunction::MapCreate => todo!(),
2117            IntrinsicFunction::MapFromSlicePair => todo!(),
2118            IntrinsicFunction::MapHas => todo!(),
2119            IntrinsicFunction::MapRemove => todo!(),
2120            IntrinsicFunction::MapIter => todo!(),
2121            IntrinsicFunction::MapIterMut => todo!(),
2122            IntrinsicFunction::MapLen => todo!(),
2123            IntrinsicFunction::MapIsEmpty => todo!(),
2124            IntrinsicFunction::MapSubscript => todo!(),
2125            IntrinsicFunction::MapSubscriptSet => todo!(),
2126            IntrinsicFunction::MapSubscriptMut => todo!(),
2127            IntrinsicFunction::MapSubscriptMutCreateIfNeeded => todo!(),
2128
2129            IntrinsicFunction::Map2GetColumn => todo!(),
2130            IntrinsicFunction::Map2GetRow => todo!(),
2131            IntrinsicFunction::Map2Remove => todo!(),
2132            IntrinsicFunction::Map2Has => todo!(),
2133            IntrinsicFunction::Map2Get => todo!(),
2134            IntrinsicFunction::Map2Insert => todo!(),
2135            IntrinsicFunction::Map2Create => todo!(),
2136
2137            // Sparse
2138            IntrinsicFunction::SparseAdd => todo!(),
2139            IntrinsicFunction::SparseNew => todo!(),
2140            IntrinsicFunction::SparseCreate => todo!(),
2141            IntrinsicFunction::SparseFromSlice => todo!(),
2142            IntrinsicFunction::SparseIter => todo!(),
2143            IntrinsicFunction::SparseIterMut => todo!(),
2144            IntrinsicFunction::SparseSubscript => todo!(),
2145            IntrinsicFunction::SparseSubscriptMut => todo!(),
2146            IntrinsicFunction::SparseHas => todo!(),
2147            IntrinsicFunction::SparseRemove => todo!(),
2148
2149            // Grid
2150            IntrinsicFunction::GridCreate => todo!(),
2151            IntrinsicFunction::GridFromSlice => todo!(),
2152            IntrinsicFunction::GridSet => todo!(),
2153            IntrinsicFunction::GridGet => todo!(),
2154            IntrinsicFunction::GridGetColumn => todo!(),
2155
2156            // Other
2157            IntrinsicFunction::Float2Magnitude => todo!(),
2158        };
2159
2160        Ok(())
2161    }
2162
2163    fn gen_intrinsic_vec_create(&self, arguments: &Vec<ArgumentExpressionOrLocation>) {
2164        for arg in arguments {
2165            info!(?arg, "argument");
2166        }
2167    }
2168
2169    fn gen_intrinsic_vec_from_slice(
2170        &mut self,
2171        arguments: &[ArgumentExpressionOrLocation],
2172        ctx: &Context,
2173    ) -> Result<(), Error> {
2174        if let ArgumentExpressionOrLocation::Expression(found_expr) = &arguments[0] {
2175            let memory = self.gen_expression_for_access(found_expr)?;
2176            self.state.builder.add_vec_from_slice(
2177                ctx.addr(),
2178                memory.addr,
2179                MemorySize(0),
2180                CountU16(0),
2181                "create vec",
2182            );
2183        } else {
2184            panic!("vec_from_slice");
2185        }
2186
2187        Ok(())
2188    }
2189
2190    fn gen_match(&mut self, match_expr: &Match, ctx: &Context) -> Result<(), Error> {
2191        let region_to_match = self.gen_for_access_or_location(&match_expr.expression)?;
2192
2193        let mut jump_to_exit_placeholders = Vec::new();
2194
2195        let arm_len_to_consider = if match_expr.contains_wildcard() {
2196            match_expr.arms.len()
2197        } else {
2198            match_expr.arms.len()
2199        };
2200        for (index, arm) in match_expr.arms.iter().enumerate() {
2201            let is_last = index == arm_len_to_consider - 1;
2202
2203            //  Each arm must set the CPU zero flag
2204            let maybe_guard = match &arm.pattern {
2205                Pattern::Normal(normal_pattern, maybe_guard) => match normal_pattern {
2206                    NormalPattern::PatternList(_) => None,
2207                    NormalPattern::EnumPattern(enum_variant, maybe_patterns) => {
2208                        self.state.builder.add_eq_u8_immediate(
2209                            region_to_match.addr,
2210                            enum_variant.common().container_index,
2211                            "check for enum variant",
2212                        );
2213                        maybe_guard.as_ref()
2214                    }
2215                    NormalPattern::Literal(_) => {
2216                        todo!()
2217                    }
2218                },
2219                Pattern::Wildcard(_) => {
2220                    // Wildcard is always true, so no comparison code is needed here at all
2221                    None
2222                }
2223            };
2224
2225            let did_add_comparison = !matches!(arm.pattern, Pattern::Wildcard(_));
2226
2227            let maybe_skip_added = if did_add_comparison {
2228                Some(
2229                    self.state
2230                        .builder
2231                        .add_jmp_if_not_equal_placeholder("placeholder for enum match"),
2232                )
2233            } else {
2234                None
2235            };
2236
2237            let maybe_guard_skip = if let Some(guard) = maybe_guard {
2238                self.gen_boolean_expression(guard)?;
2239                // z flag should have been updated now
2240
2241                Some(
2242                    self.state
2243                        .builder
2244                        .add_jmp_if_not_equal_placeholder("placeholder for skip guard"),
2245                )
2246            } else {
2247                None
2248            };
2249
2250            self.gen_expression(&arm.expression, ctx)?;
2251
2252            if !is_last {
2253                let jump_to_exit_placeholder =
2254                    self.state.builder.add_jump_placeholder("jump to exit");
2255                jump_to_exit_placeholders.push(jump_to_exit_placeholder);
2256            }
2257
2258            if let Some(skip) = maybe_skip_added {
2259                self.state.builder.patch_jump_here(skip);
2260            }
2261            if let Some(guard_skip) = maybe_guard_skip {
2262                self.state.builder.patch_jump_here(guard_skip);
2263            }
2264        }
2265
2266        for placeholder in jump_to_exit_placeholders {
2267            self.state.builder.patch_jump_here(placeholder);
2268        }
2269
2270        Ok(())
2271    }
2272
2273    fn gen_guard(&mut self, guards: &Vec<Guard>, ctx: &Context) -> Result<(), Error> {
2274        let mut jump_to_exit_placeholders = Vec::new();
2275        for guard in guards {
2276            if let Some(condition) = &guard.condition {
2277                self.gen_boolean_expression(condition); // update z flag
2278                let skip_expression_patch = self
2279                    .state
2280                    .builder
2281                    .add_jmp_if_not_equal_placeholder("guard condition");
2282                self.gen_expression(&guard.result, ctx)?;
2283                let jump_to_exit_placeholder =
2284                    self.state.builder.add_jump_placeholder("jump to exit");
2285                jump_to_exit_placeholders.push(jump_to_exit_placeholder);
2286                self.state.builder.patch_jump_here(skip_expression_patch);
2287            } else {
2288                // _ -> wildcard
2289                self.gen_expression(&guard.result, ctx)?;
2290            }
2291        }
2292
2293        for placeholder in jump_to_exit_placeholders {
2294            self.state.builder.patch_jump_here(placeholder);
2295        }
2296
2297        Ok(())
2298    }
2299
2300    fn gen_when(
2301        &mut self,
2302        bindings: &Vec<WhenBinding>,
2303        true_expr: &Expression,
2304        maybe_false_expr: Option<&Expression>,
2305        ctx: &Context,
2306    ) -> Result<(), Error> {
2307        let mut all_false_jumps = Vec::new();
2308
2309        for binding in bindings {
2310            let (variable_region, _alignment) = self.get_variable_region(&binding.variable);
2311
2312            let old_variable_region = self.gen_for_access_or_location(&binding.expr)?;
2313
2314            self.state
2315                .builder
2316                .add_tst8(old_variable_region.addr, "check binding");
2317            let patch = self
2318                .state
2319                .builder
2320                .add_jmp_if_not_equal_placeholder("jump if none");
2321            all_false_jumps.push(patch);
2322        }
2323
2324        // if we are here all bindings are `Some`
2325        for binding in bindings {
2326            let (variable_region, alignment) = self.get_variable_region(&binding.variable);
2327
2328            if binding.has_expression() {
2329                let var_ctx = Context::new(variable_region);
2330                self.gen_mut_or_immute(&binding.expr, &var_ctx)?;
2331            } else {
2332                let ArgumentExpressionOrLocation::Expression(variable_access_expression) =
2333                    &binding.expr.expression_or_location
2334                else {
2335                    panic!("must be expression");
2336                };
2337                let old_variable_region =
2338                    self.gen_expression_for_access(variable_access_expression)?;
2339                let alignment_offset: MemoryOffset = alignment.into();
2340                let some_value_region = FrameMemoryRegion::new(
2341                    old_variable_region.addr.advance(alignment_offset),
2342                    MemorySize(variable_region.size.0),
2343                );
2344                self.state.builder.add_movlp(
2345                    variable_region.addr,
2346                    some_value_region.addr,
2347                    some_value_region.size,
2348                    "move from Some to value",
2349                );
2350            }
2351        }
2352
2353        self.gen_expression(true_expr, ctx)?;
2354        let maybe_jump_over_false = if let Some(_else_expr) = maybe_false_expr {
2355            Some(
2356                self.state
2357                    .builder
2358                    .add_jump_placeholder("jump over false section"),
2359            )
2360        } else {
2361            None
2362        };
2363
2364        for false_jump_patch in all_false_jumps {
2365            self.state.builder.patch_jump_here(false_jump_patch);
2366        }
2367
2368        if let Some(else_expr) = maybe_false_expr {
2369            self.gen_expression(else_expr, ctx);
2370            self.state
2371                .builder
2372                .patch_jump_here(maybe_jump_over_false.unwrap());
2373        }
2374
2375        Ok(())
2376    }
2377
2378    fn create_err(&mut self, kind: ErrorKind, node: &Node) -> Error {
2379        error!(?kind, "encountered error");
2380        Error {
2381            kind,
2382            node: node.clone(),
2383        }
2384    }
2385
2386    fn gen_tuple_destructuring(
2387        &mut self,
2388        target_variables: &Vec<VariableRef>,
2389        tuple_type: &Vec<Type>,
2390        source_tuple_expression: &Expression,
2391    ) -> Result<(), Error> {
2392        let source_region = self.gen_expression_for_access(source_tuple_expression)?;
2393
2394        let (total_size, _max_alignment, element_offsets) = layout_tuple_elements(tuple_type);
2395        assert_eq!(total_size.0, source_region.size.0);
2396
2397        for (target_variable, (element_offset, element_size)) in
2398            target_variables.iter().zip(element_offsets)
2399        {
2400            if target_variable.is_unused {
2401            } else {
2402                let (target_region, _variable_alignment) =
2403                    self.get_variable_region(target_variable);
2404                assert_eq!(target_region.size.0, element_size.0);
2405
2406                let source_element_region = FrameMemoryRegion::new(
2407                    source_region.addr.advance(element_offset),
2408                    element_size,
2409                );
2410                self.state.builder.add_mov(
2411                    target_region.addr,
2412                    source_element_region.addr,
2413                    source_element_region.size,
2414                    &format!(
2415                        "destructuring to variable {}",
2416                        target_variable.assigned_name
2417                    ),
2418                );
2419            }
2420        }
2421
2422        Ok(())
2423    }
2424
2425    fn gen_constant_access(
2426        &mut self,
2427        constant_reference: &ConstantRef,
2428        ctx: &Context,
2429    ) -> Result<(), Error> {
2430        let constant_region = self
2431            .state
2432            .constant_offsets
2433            .get(&constant_reference.id)
2434            .unwrap();
2435        assert_eq!(constant_region.size.0, ctx.target_size().0);
2436
2437        self.state.builder.add_ld_constant(
2438            ctx.addr(),
2439            constant_region.addr,
2440            constant_region.size,
2441            &format!("load constant '{}'", constant_reference.assigned_name),
2442        );
2443
2444        Ok(())
2445    }
2446}
2447
2448fn single_intrinsic_fn(body: &Expression) -> Option<&IntrinsicFunction> {
2449    let ExpressionKind::Block(block_expressions) = &body.kind else {
2450        panic!("function body should be a block")
2451    };
2452
2453    if let ExpressionKind::IntrinsicCallEx(found_intrinsic_fn, _non_instantiated_arguments) =
2454        &block_expressions[0].kind
2455    {
2456        Some(found_intrinsic_fn)
2457    } else {
2458        None
2459    }
2460}
2461
2462fn struct_field_offset(
2463    index_to_look_for: usize,
2464    anon_struct_type: &AnonymousStructType,
2465) -> (MemoryOffset, MemorySize, MemoryAlignment) {
2466    let mut offset = MemoryOffset(0);
2467    for (field_index, (_name, field)) in
2468        anon_struct_type.field_name_sorted_fields.iter().enumerate()
2469    {
2470        let (field_size, field_alignment) = type_size_and_alignment(&field.field_type);
2471        let field_start_offset = offset.space(field_size, field_alignment);
2472        if field_index == index_to_look_for {
2473            return (field_start_offset, field_size, field_alignment);
2474        }
2475    }
2476
2477    panic!("field index is wrong")
2478}