swamp_script_code_gen/
lib.rs

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