swamp_script_analyzer/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/script
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod access;
6pub mod call;
7pub mod constant;
8pub mod def;
9pub mod err;
10pub mod internal;
11pub mod literal;
12pub mod lookup;
13pub mod operator;
14pub mod pattern;
15pub mod prelude;
16mod structure;
17pub mod types;
18pub mod variable;
19use crate::err::{Error, ErrorKind};
20use seq_map::SeqMap;
21use std::mem::take;
22use std::num::{ParseFloatError, ParseIntError};
23use std::rc::Rc;
24use swamp_script_semantic::modules::ModuleRef;
25use swamp_script_semantic::prelude::*;
26use swamp_script_semantic::symtbl::{FuncDef, Symbol, SymbolTable, SymbolTableRef};
27use swamp_script_semantic::{
28    ArgumentExpressionOrLocation, LocationAccess, LocationAccessKind, MutOrImmutableExpression,
29    NormalPattern, Postfix, PostfixKind, RangeMode, SingleLocationExpression,
30    SingleLocationExpressionKind, SingleMutLocationExpression, TypeWithMut, WhenBinding,
31};
32use swamp_script_source_map::SourceMap;
33use tracing::error;
34use tracing::info;
35
36#[must_use]
37pub fn convert_range_mode(range_mode: &swamp_script_ast::RangeMode) -> RangeMode {
38    match range_mode {
39        swamp_script_ast::RangeMode::Inclusive => RangeMode::Inclusive,
40        swamp_script_ast::RangeMode::Exclusive => RangeMode::Exclusive,
41    }
42}
43
44#[derive(Copy, Clone, Eq, PartialEq, Debug)]
45pub enum LocationSide {
46    Lhs,
47    Rhs,
48}
49
50#[derive(Debug)]
51pub struct AutoUseModules {
52    pub modules: Vec<SymbolTableRef>,
53}
54
55#[derive(Debug)]
56pub struct Program {
57    pub state: ProgramState,
58    pub modules: Modules,
59    pub auto_use_modules: AutoUseModules,
60}
61
62impl Default for Program {
63    fn default() -> Self {
64        Self::new()
65    }
66}
67
68impl Program {
69    #[must_use]
70    pub fn new() -> Self {
71        Self {
72            state: ProgramState::new(),
73            modules: Modules::new(),
74            auto_use_modules: AutoUseModules {
75                modules: Vec::new(),
76            },
77        }
78    }
79}
80
81#[must_use]
82pub const fn convert_span(without: &swamp_script_ast::SpanWithoutFileId, file_id: FileId) -> Span {
83    Span {
84        file_id,
85        offset: without.offset,
86        length: without.length,
87    }
88}
89
90pub const SPARSE_TYPE_ID: TypeNumber = 999;
91pub const SPARSE_ID_TYPE_ID: TypeNumber = 998;
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum TypeContextScope {
95    InsideFunction, // Allow return, but not break
96    InsideLoop,     // Allow break and return
97    /// Inside both a function and a loop
98    /// Allows: return, break, and continue
99    InsideBothFunctionAndLoop,
100    ArgumentOrOutsideFunction, // Allow neither break nor return
101}
102
103impl TypeContextScope {
104    /// Returns true if return statements are allowed in this scope
105    #[must_use]
106    pub fn allows_return(&self) -> bool {
107        matches!(self, Self::InsideFunction | Self::InsideBothFunctionAndLoop)
108    }
109
110    /// Returns true if break statements are allowed in this scope
111    #[must_use]
112    pub fn allows_break(&self) -> bool {
113        matches!(self, Self::InsideLoop | Self::InsideBothFunctionAndLoop)
114    }
115
116    /// Returns true if continue statements are allowed in this scope
117    #[must_use]
118    pub fn allows_continue(&self) -> bool {
119        self.allows_break() // Same rules as break
120    }
121
122    /// Creates a new scope when entering a function
123    #[must_use]
124    pub fn enter_function(&self) -> Self {
125        match self {
126            Self::ArgumentOrOutsideFunction => Self::InsideFunction,
127            Self::InsideLoop => Self::InsideBothFunctionAndLoop,
128            _ => *self,
129        }
130    }
131
132    /// Creates a new scope when entering a loop
133    #[must_use]
134    pub fn enter_loop(&self) -> Self {
135        match self {
136            Self::ArgumentOrOutsideFunction => Self::InsideLoop,
137            Self::InsideFunction => Self::InsideBothFunctionAndLoop,
138            _ => *self,
139        }
140    }
141}
142
143/// Type checking context
144#[derive(Debug, Clone)]
145pub struct TypeContext<'a> {
146    /// Expected type for the current expression
147    pub expected_type: Option<&'a Type>,
148
149    /// Return type of the enclosing function
150    pub return_type: Option<&'a Type>,
151
152    pub scope: TypeContextScope,
153
154    pub is_in_compare_like: bool,
155}
156
157impl TypeContext<'_> {
158    pub(crate) fn allows_continue(&self) -> bool {
159        self.scope.allows_continue() && self.is_in_compare_like
160    }
161}
162
163impl TypeContext<'_> {
164    pub(crate) fn allows_return(&self) -> bool {
165        self.scope.allows_return() && self.is_in_compare_like
166    }
167}
168
169impl TypeContext<'_> {
170    pub(crate) fn allows_break(&self) -> bool {
171        self.scope.allows_break()
172    }
173}
174
175impl<'a> TypeContext<'a> {
176    #[must_use]
177    pub const fn new(
178        expected_type: Option<&'a Type>,
179        return_type: Option<&'a Type>,
180        scope: TypeContextScope,
181    ) -> Self {
182        Self {
183            expected_type,
184            return_type,
185            scope,
186            is_in_compare_like: false,
187        }
188    }
189
190    pub const fn new_argument(required_type: &'a Type) -> Self {
191        Self {
192            expected_type: Some(required_type),
193            return_type: None,
194            scope: TypeContextScope::ArgumentOrOutsideFunction,
195            is_in_compare_like: false,
196        }
197    }
198
199    #[must_use]
200    pub const fn new_unsure_argument(expected_type: Option<&'a Type>) -> Self {
201        Self {
202            expected_type,
203            return_type: None,
204            scope: TypeContextScope::ArgumentOrOutsideFunction,
205            is_in_compare_like: false,
206        }
207    }
208
209    #[must_use]
210    pub const fn new_anything_argument() -> Self {
211        Self {
212            expected_type: None,
213            return_type: None,
214            scope: TypeContextScope::ArgumentOrOutsideFunction,
215            is_in_compare_like: false,
216        }
217    }
218
219    pub fn new_function(required_type: &'a Type) -> Self {
220        Self {
221            expected_type: Some(required_type),
222            return_type: Some(required_type),
223            scope: TypeContextScope::InsideFunction,
224            is_in_compare_like: false,
225        }
226    }
227
228    #[must_use]
229    pub const fn with_expected_type(&self, expected_type: Option<&'a Type>) -> Self {
230        Self {
231            expected_type,
232            return_type: self.return_type,
233            scope: self.scope,
234            is_in_compare_like: self.is_in_compare_like,
235        }
236    }
237
238    pub(crate) const fn we_know_expected_type(&self, found_type: &'a Type) -> Self {
239        self.with_expected_type(Some(found_type))
240    }
241
242    /// # Panics
243    ///
244    #[must_use]
245    pub const fn for_return(&self) -> Self {
246        Self {
247            expected_type: Some(self.return_type.unwrap()),
248            return_type: Some(self.return_type.unwrap()),
249            scope: TypeContextScope::ArgumentOrOutsideFunction,
250            is_in_compare_like: false,
251        }
252    }
253
254    #[must_use]
255    pub fn enter_function(&self, required_type: &'a Type) -> Self {
256        Self {
257            expected_type: Some(required_type),
258            return_type: Some(required_type),
259            scope: self.scope.enter_function(),
260            is_in_compare_like: false,
261        }
262    }
263
264    /// Creates a new scope when entering a loop
265    #[must_use]
266    pub fn enter_loop(&self) -> Self {
267        Self {
268            expected_type: self.expected_type,
269            return_type: self.return_type,
270            scope: self.scope.enter_loop(),
271            is_in_compare_like: self.is_in_compare_like,
272        }
273    }
274
275    /// Creates a new scope when entering a loop
276    #[must_use]
277    pub fn enter_compare(&self) -> Self {
278        Self {
279            expected_type: self.expected_type,
280            return_type: self.return_type,
281            scope: self.scope.enter_loop(),
282            is_in_compare_like: true,
283        }
284    }
285}
286
287#[derive(Debug, Eq, PartialEq)]
288pub enum BlockScopeMode {
289    Open,
290    Closed,
291}
292
293#[derive(Debug)]
294pub struct BlockScope {
295    mode: BlockScopeMode,
296    variables: SeqMap<String, VariableRef>,
297}
298
299impl Default for BlockScope {
300    fn default() -> Self {
301        Self::new()
302    }
303}
304
305impl BlockScope {
306    #[must_use]
307    pub fn new() -> Self {
308        Self {
309            mode: BlockScopeMode::Open,
310            variables: SeqMap::new(),
311        }
312    }
313}
314
315pub struct SharedState<'a> {
316    pub state: &'a mut ProgramState,
317    pub lookup_table: SymbolTable,
318    pub definition_table: SymbolTable,
319    pub modules: &'a Modules,
320    pub source_map: &'a SourceMap,
321    pub file_id: FileId,
322}
323
324impl<'a> SharedState<'a> {
325    #[must_use]
326    pub fn get_symbol_table(&'a self, path: &[String]) -> Option<&'a SymbolTable> {
327        if path.is_empty() {
328            return Some(&self.lookup_table);
329        }
330        self.get_module(path)
331            .map_or(None, |module| Some(&module.namespace.symbol_table))
332    }
333
334    #[must_use]
335    pub fn get_module(&'a self, path: &[String]) -> Option<&'a ModuleRef> {
336        let resolved_path = {
337            self.lookup_table.get_package_version(&path[0]).map_or_else(
338                || path.to_vec(),
339                |found_version| {
340                    let mut new_path = path.to_vec();
341                    let complete_name = format!("{}-{found_version}", path[0]);
342                    info!(path=?path[0], found_version, complete_name, "switched out version");
343                    new_path[0] = complete_name;
344                    new_path
345                },
346            )
347        };
348
349        if path.len() == 1 {
350            if let Some(module_ref) = self.lookup_table.get_module_link(&path[0]) {
351                return Some(module_ref);
352            }
353        }
354
355        if let Some(x) = self.modules.get(&resolved_path) {
356            return Some(x);
357        }
358
359        None
360    }
361}
362
363pub struct FunctionScopeState {
364    pub block_scope_stack: Vec<BlockScope>,
365    pub return_type: Type,
366}
367
368impl FunctionScopeState {
369    #[must_use]
370    pub fn new(return_type: Type) -> Self {
371        Self {
372            block_scope_stack: vec![BlockScope::new()],
373            return_type,
374        }
375    }
376}
377
378pub struct Analyzer<'a> {
379    pub shared: SharedState<'a>,
380    scope: FunctionScopeState,
381    global: FunctionScopeState,
382}
383
384impl<'a> Analyzer<'a> {
385    pub fn new(
386        state: &'a mut ProgramState,
387        modules: &'a Modules,
388        source_map: &'a SourceMap,
389        file_id: FileId,
390    ) -> Self {
391        let shared = SharedState {
392            state,
393            lookup_table: SymbolTable::default(),
394            definition_table: SymbolTable::default(),
395            modules,
396            source_map,
397            file_id,
398        };
399        Self {
400            scope: FunctionScopeState::new(Type::Unit),
401            global: FunctionScopeState::new(Type::Unit),
402            shared,
403        }
404    }
405
406    fn start_function(&mut self, return_type: Type) {
407        self.global.block_scope_stack = take(&mut self.scope.block_scope_stack);
408        self.scope = FunctionScopeState::new(return_type);
409    }
410
411    fn stop_function(&mut self) {
412        self.scope.block_scope_stack = take(&mut self.global.block_scope_stack);
413    }
414
415    fn analyze_if_expression(
416        &mut self,
417        condition: &swamp_script_ast::Expression,
418        true_expression: &swamp_script_ast::Expression,
419        maybe_false_expression: Option<&swamp_script_ast::Expression>,
420        context: &TypeContext,
421    ) -> Result<Expression, Error> {
422        let resolved_condition = self.analyze_bool_argument_expression(condition)?;
423
424        let branch_context = context.enter_compare();
425
426        let true_expr = self.analyze_expression(true_expression, &branch_context)?;
427        let resolved_true = Box::new(true_expr);
428
429        let mut detected = context.expected_type.cloned();
430        if detected.is_none() && !matches!(resolved_true.ty, Type::Never) {
431            detected = Some(resolved_true.ty.clone());
432        }
433
434        // Analyze the false branch if it exists
435        let else_statements = if let Some(false_expression) = maybe_false_expression {
436            let else_context = branch_context.with_expected_type(detected.as_ref());
437            let else_expr = self.analyze_expression(false_expression, &else_context)?;
438            if detected.is_none() && !matches!(else_expr.ty, Type::Never) {
439                detected = Some(else_expr.ty.clone());
440            }
441
442            Some(Box::new(else_expr))
443        } else {
444            None
445        };
446
447        Ok(self.create_expr(
448            ExpressionKind::If(resolved_condition, resolved_true, else_statements),
449            detected.unwrap(),
450            &condition.node,
451        ))
452    }
453
454    fn get_text(&self, ast_node: &swamp_script_ast::Node) -> &str {
455        let span = Span {
456            file_id: self.shared.file_id,
457            offset: ast_node.span.offset,
458            length: ast_node.span.length,
459        };
460        self.shared.source_map.get_span_source(
461            self.shared.file_id,
462            span.offset as usize,
463            span.length as usize,
464        )
465    }
466
467    fn get_text_resolved(&self, resolved_node: &Node) -> &str {
468        let span = Span {
469            file_id: self.shared.file_id,
470            offset: resolved_node.span.offset,
471            length: resolved_node.span.length,
472        };
473        self.shared.source_map.get_span_source(
474            self.shared.file_id,
475            span.offset as usize,
476            span.length as usize,
477        )
478    }
479
480    fn get_path(&self, ident: &swamp_script_ast::QualifiedTypeIdentifier) -> (Vec<String>, String) {
481        let path = ident
482            .module_path
483            .as_ref()
484            .map_or_else(Vec::new, |found_path| {
485                let mut v = Vec::new();
486                for p in &found_path.0 {
487                    v.push(self.get_text(p).to_string());
488                }
489                v
490            });
491        (path, self.get_text(&ident.name.0).to_string())
492    }
493
494    fn analyze_return_type(
495        &mut self,
496        function: &swamp_script_ast::Function,
497    ) -> Result<Type, Error> {
498        let ast_return_type = match function {
499            swamp_script_ast::Function::Internal(x) => &x.declaration.return_type,
500            swamp_script_ast::Function::External(x) => &x.return_type,
501        };
502
503        let resolved_return_type = match ast_return_type {
504            None => Type::Unit,
505            Some(x) => self.analyze_type(x)?,
506        };
507
508        Ok(resolved_return_type)
509    }
510
511    fn analyze_statements_in_function(
512        &mut self,
513        expression: &swamp_script_ast::Expression,
514        return_type: &Type,
515    ) -> Result<Expression, Error> {
516        let function_context = TypeContext::new_function(return_type);
517        let resolved_statement = self.analyze_expression(expression, &function_context)?;
518        //let wrapped_expr = Self::check_and_wrap_return_value(resolved_statement, return_type)?;
519
520        Ok(resolved_statement)
521    }
522
523    fn analyze_maybe_type(
524        &mut self,
525        maybe_type: Option<&swamp_script_ast::Type>,
526    ) -> Result<Type, Error> {
527        let found_type = match maybe_type {
528            None => Type::Unit,
529            Some(ast_type) => self.analyze_type(ast_type)?,
530        };
531        Ok(found_type)
532    }
533
534    fn analyze_for_pattern(
535        &mut self,
536        pattern: &swamp_script_ast::ForPattern,
537        key_type: Option<&Type>,
538        value_type: &Type,
539    ) -> Result<ForPattern, Error> {
540        match pattern {
541            swamp_script_ast::ForPattern::Single(var) => {
542                let variable_ref = self.create_local_variable(
543                    &var.identifier,
544                    Option::from(&var.is_mut),
545                    value_type,
546                )?;
547                Ok(ForPattern::Single(variable_ref))
548            }
549            swamp_script_ast::ForPattern::Pair(first, second) => {
550                let found_key = key_type.unwrap();
551                let first_var_ref = self.create_local_variable(
552                    &first.identifier,
553                    Option::from(&first.is_mut),
554                    found_key,
555                )?;
556                let second_var_ref = self.create_local_variable(
557                    &second.identifier,
558                    Option::from(&second.is_mut),
559                    value_type,
560                )?;
561                Ok(ForPattern::Pair(first_var_ref, second_var_ref))
562            }
563        }
564    }
565
566    fn analyze_parameters(
567        &mut self,
568        parameters: &Vec<swamp_script_ast::Parameter>,
569    ) -> Result<Vec<TypeForParameter>, Error> {
570        let mut resolved_parameters = Vec::new();
571        for parameter in parameters {
572            let param_type = self.analyze_type(&parameter.param_type)?;
573            resolved_parameters.push(TypeForParameter {
574                name: self.get_text(&parameter.variable.name).to_string(),
575                resolved_type: param_type,
576                is_mutable: parameter.variable.is_mutable.is_some(),
577                node: Some(ParameterNode {
578                    is_mutable: self.to_node_option(Option::from(&parameter.variable.is_mutable)),
579                    name: self.to_node(&parameter.variable.name),
580                }),
581            });
582        }
583        Ok(resolved_parameters)
584    }
585
586    #[must_use]
587    pub fn is_empty_array_literal(ast_expression: &swamp_script_ast::Expression) -> bool {
588        matches!(&ast_expression.kind, swamp_script_ast::ExpressionKind::Literal(swamp_script_ast::LiteralKind::Array(items)) if items.is_empty())
589    }
590
591    pub fn analyze_immutable_argument(
592        &mut self,
593        ast_expression: &swamp_script_ast::Expression,
594        expected_type: &Type,
595    ) -> Result<Expression, Error> {
596        let context = TypeContext::new_argument(expected_type);
597        self.analyze_expression(ast_expression, &context)
598    }
599
600    pub fn analyze_start_chain_expression_get_mutability(
601        &mut self,
602        ast_expression: &swamp_script_ast::Expression,
603        expected_type: Option<&Type>,
604    ) -> Result<(Expression, bool), Error> {
605        let any_parameter_context = TypeContext::new_unsure_argument(expected_type);
606        let resolved = self.analyze_expression(ast_expression, &any_parameter_context)?;
607        let mutability = match resolved.kind {
608            ExpressionKind::VariableAccess(ref resolved_variable) => resolved_variable.is_mutable(),
609            _ => false,
610        };
611
612        Ok((resolved, mutability))
613    }
614
615    fn analyze_function_body_expression(
616        &mut self,
617        expression: &swamp_script_ast::Expression,
618        return_type: &Type,
619    ) -> Result<Expression, Error> {
620        let context = TypeContext::new_function(return_type);
621        let resolved_statement = self.analyze_expression(expression, &context)?;
622        //let wrapped_expr = Self::check_and_wrap_return_value(resolved_statement, return_type)?;
623
624        Ok(resolved_statement)
625    }
626
627    /// # Errors
628    ///
629    #[allow(clippy::too_many_lines)]
630    pub fn analyze_expression(
631        &mut self,
632        ast_expression: &swamp_script_ast::Expression,
633        context: &TypeContext,
634    ) -> Result<Expression, Error> {
635        let expr = self.analyze_expression_internal(ast_expression, context)?;
636
637        let encountered_type = expr.ty.clone();
638
639        // If there's an expected type, check compatibility and handle coercions
640        if let Some(found_expected_type) = context.expected_type {
641            if found_expected_type.compatible_with(&encountered_type) {
642                return Ok(expr);
643            } else if !matches!(encountered_type, Type::Optional(_)) {
644                // If an optional is expected, we can wrap it
645                if let Type::Optional(expected_inner_type) = found_expected_type {
646                    if encountered_type.compatible_with(expected_inner_type) {
647                        let wrapped = self.create_expr(
648                            ExpressionKind::Option(Option::from(Box::new(expr))),
649                            found_expected_type.clone(),
650                            &ast_expression.node,
651                        );
652                        return Ok(wrapped);
653                    }
654                }
655            } else if matches!(found_expected_type, &Type::Bool) {
656                if let Type::Optional(_inner_type) = encountered_type {
657                    let wrapped = self.create_expr(
658                        ExpressionKind::CoerceOptionToBool(Box::from(expr)),
659                        Type::Bool,
660                        &ast_expression.node,
661                    );
662                    return Ok(wrapped);
663                }
664            }
665
666            error!(?expr, ?ast_expression, "expr");
667            error!(
668                ?found_expected_type,
669                ?encountered_type,
670                "incompatible types"
671            );
672            return Err(self.create_err(
673                ErrorKind::IncompatibleTypes(found_expected_type.clone(), encountered_type),
674                &ast_expression.node,
675            ));
676        }
677
678        Ok(expr)
679    }
680
681    /// # Errors
682    ///
683    #[allow(clippy::too_many_lines)]
684    pub fn analyze_expression_internal(
685        &mut self,
686        ast_expression: &swamp_script_ast::Expression,
687        context: &TypeContext,
688    ) -> Result<Expression, Error> {
689        //info!(?ast_expression, "resolving");
690        let expression = match &ast_expression.kind {
691            swamp_script_ast::ExpressionKind::Break => {
692                self.analyze_break(context, &ast_expression.node)?
693            }
694
695            swamp_script_ast::ExpressionKind::Return(optional_expression) => self.analyze_return(
696                context,
697                optional_expression.as_deref(),
698                &ast_expression.node,
699            )?,
700
701            swamp_script_ast::ExpressionKind::Continue => {
702                self.analyze_continue(context, &ast_expression.node)?
703            }
704
705            // Lookups
706            swamp_script_ast::ExpressionKind::PostfixChain(postfix_chain) => {
707                self.analyze_postfix_chain(postfix_chain)?
708            }
709
710            swamp_script_ast::ExpressionKind::IdentifierReference(variable) => {
711                self.analyze_identifier_reference(&variable.name)?
712            }
713            swamp_script_ast::ExpressionKind::VariableDefinition(
714                variable,
715                coerce_type,
716                source_expression,
717            ) => self.analyze_create_variable(
718                variable,
719                Option::from(coerce_type),
720                source_expression,
721            )?,
722
723            swamp_script_ast::ExpressionKind::VariableAssignment(variable, source_expression) => {
724                self.analyze_variable_assignment(variable, source_expression)?
725            }
726            swamp_script_ast::ExpressionKind::DestructuringAssignment(variables, expression) => {
727                self.analyze_destructuring(&ast_expression.node, variables, expression)?
728            }
729
730            swamp_script_ast::ExpressionKind::StaticFunctionReference(qualified_identifier) => {
731                self.analyze_static_function_access(qualified_identifier)?
732            }
733
734            swamp_script_ast::ExpressionKind::StaticMemberFunctionReference(
735                type_identifier,
736                member_name,
737            ) => self.analyze_static_member_access(type_identifier, member_name)?,
738
739            swamp_script_ast::ExpressionKind::ConstantReference(constant_identifier) => {
740                self.analyze_constant_access(constant_identifier)?
741            }
742
743            swamp_script_ast::ExpressionKind::FunctionReference(qualified_identifier) => {
744                self.analyze_static_function_access(qualified_identifier)?
745            }
746
747            swamp_script_ast::ExpressionKind::Assignment(location, source) => {
748                self.analyze_assignment(location, source)?
749            }
750            swamp_script_ast::ExpressionKind::CompoundAssignment(target, op, source) => {
751                self.analyze_assignment_compound(target, op, source)?
752            }
753
754            // Operator
755            swamp_script_ast::ExpressionKind::BinaryOp(resolved_a, operator, resolved_b) => {
756                let (resolved_op, result_type) =
757                    self.analyze_binary_op(resolved_a, operator, resolved_b)?;
758
759                self.create_expr(
760                    ExpressionKind::BinaryOp(resolved_op),
761                    result_type,
762                    &ast_expression.node,
763                )
764            }
765            swamp_script_ast::ExpressionKind::UnaryOp(operator, expression) => {
766                let (resolved_op, result_type) = self.analyze_unary_op(operator, expression)?;
767                self.create_expr(
768                    ExpressionKind::UnaryOp(resolved_op),
769                    result_type,
770                    &ast_expression.node,
771                )
772            }
773
774            swamp_script_ast::ExpressionKind::Block(expressions) => {
775                let (block, resulting_type) =
776                    self.analyze_block(&ast_expression.node, context, expressions)?;
777                self.create_expr(
778                    ExpressionKind::Block(block),
779                    resulting_type,
780                    &ast_expression.node,
781                )
782            }
783
784            swamp_script_ast::ExpressionKind::With(variable_bindings, expression) => {
785                self.analyze_with_expr(context, variable_bindings, expression)?
786            }
787
788            swamp_script_ast::ExpressionKind::When(variable_bindings, true_expr, else_expr) => {
789                self.analyze_when_expr(context, variable_bindings, true_expr, else_expr.as_deref())?
790            }
791
792            swamp_script_ast::ExpressionKind::InterpolatedString(string_parts) => {
793                let kind = ExpressionKind::InterpolatedString(
794                    self.analyze_interpolated_string(string_parts)?,
795                );
796
797                self.create_expr(kind, Type::String, &ast_expression.node)
798            }
799
800            // Creation
801            swamp_script_ast::ExpressionKind::StructLiteral(
802                struct_identifier,
803                fields,
804                has_rest,
805            ) => self.analyze_struct_instantiation(struct_identifier, fields, *has_rest)?,
806
807            swamp_script_ast::ExpressionKind::Range(min_value, max_value, range_mode) => {
808                let range = self.analyze_range(min_value, max_value, range_mode)?;
809                self.create_expr(
810                    ExpressionKind::Range(Box::from(range.min), Box::from(range.max), range.mode),
811                    Type::Iterable(Box::from(Type::Int)),
812                    &ast_expression.node,
813                )
814            }
815
816            swamp_script_ast::ExpressionKind::Literal(literal) => {
817                let (literal, resolved_type) =
818                    self.analyze_literal(&ast_expression.node, literal, context)?;
819                self.create_expr(
820                    ExpressionKind::Literal(literal),
821                    resolved_type,
822                    &ast_expression.node,
823                )
824            }
825
826            swamp_script_ast::ExpressionKind::ForLoop(
827                pattern,
828                iteratable_expression,
829                statements,
830            ) => {
831                let resolved_iterator =
832                    self.analyze_iterable(pattern.any_mut(), &iteratable_expression.expression)?;
833
834                self.push_block_scope("for_loop");
835                let pattern = self.analyze_for_pattern(
836                    pattern,
837                    resolved_iterator.key_type.as_ref(),
838                    &resolved_iterator.value_type,
839                )?;
840                let resolved_statements =
841                    self.analyze_expression(statements, &context.enter_loop())?;
842                self.pop_block_scope("for_loop");
843                let resolved_type = resolved_statements.ty.clone();
844                self.create_expr(
845                    ExpressionKind::ForLoop(
846                        pattern,
847                        resolved_iterator,
848                        Box::from(resolved_statements),
849                    ),
850                    resolved_type,
851                    &ast_expression.node,
852                )
853            }
854            swamp_script_ast::ExpressionKind::WhileLoop(expression, statements) => {
855                let condition = self.analyze_bool_argument_expression(expression)?;
856                //self.push_block_scope("while_loop");
857                let resolved_statements =
858                    self.analyze_expression(statements, &context.enter_loop())?;
859                let resolved_type = resolved_statements.ty.clone();
860                //self.pop_block_scope("while_loop");
861
862                self.create_expr(
863                    ExpressionKind::WhileLoop(condition, Box::from(resolved_statements)),
864                    resolved_type,
865                    &ast_expression.node,
866                )
867            }
868
869            swamp_script_ast::ExpressionKind::If(
870                expression,
871                true_expression,
872                maybe_false_expression,
873            ) => self.analyze_if_expression(
874                expression,
875                true_expression,
876                maybe_false_expression.as_deref(),
877                context,
878            )?,
879
880            swamp_script_ast::ExpressionKind::Match(expression, arms) => {
881                let (match_expr, return_type) = self.analyze_match(expression, context, arms)?;
882                self.create_expr(
883                    ExpressionKind::Match(match_expr),
884                    return_type,
885                    &ast_expression.node,
886                )
887            }
888            swamp_script_ast::ExpressionKind::Guard(guard_expressions) => {
889                self.analyze_guard(&ast_expression.node, context, guard_expressions)?
890            }
891        };
892
893        //info!(ty=%expression.ty, kind=?expression.kind,  "resolved expression");
894
895        Ok(expression)
896    }
897
898    fn get_struct_type(
899        &mut self,
900        qualified_type_identifier: &swamp_script_ast::QualifiedTypeIdentifier,
901    ) -> Result<StructTypeRef, Error> {
902        let maybe_struct_type = self.analyze_named_type(qualified_type_identifier)?;
903        match maybe_struct_type {
904            Type::Struct(struct_type) => Ok(struct_type),
905            _ => Err(self.create_err(
906                // For other Type variants that are not Struct
907                ErrorKind::UnknownStructTypeReference,
908                &qualified_type_identifier.name.0,
909            )),
910        }
911    }
912
913    pub fn check_built_in_type(s: &str) -> Option<Type> {
914        let found = match s {
915            "Int" => Type::Int,
916            "Float" => Type::Float,
917            "Bool" => Type::Bool,
918            "String" => Type::String,
919            _ => return None,
920        };
921        Some(found)
922    }
923
924    pub(crate) fn analyze_named_type(
925        &mut self,
926        type_name_to_find: &swamp_script_ast::QualifiedTypeIdentifier,
927    ) -> Result<Type, Error> {
928        let (path, name) = self.get_path(type_name_to_find);
929        // TODO: the built in should be put in the symbol table
930        if let Some(ty) = Self::check_built_in_type(&name) {
931            return Ok(ty);
932        }
933
934        let symbol = {
935            let maybe_symbol_table = self.shared.get_symbol_table(&path);
936            let symbol_table = maybe_symbol_table.ok_or_else(|| {
937                self.create_err(ErrorKind::UnknownSymbol, &type_name_to_find.name.0)
938            })?;
939            symbol_table
940                .get_symbol(&name)
941                .ok_or_else(|| {
942                    self.create_err(ErrorKind::UnknownSymbol, &type_name_to_find.name.0)
943                })?
944                .clone()
945        };
946
947        let mut analyzed_types = Vec::new();
948
949        for analyzed_type in &type_name_to_find.generic_params {
950            let ty = self.analyze_type(analyzed_type)?;
951
952            analyzed_types.push(ty);
953        }
954
955        let result_type = match symbol {
956            Symbol::Type(base_type) => base_type,
957            Symbol::Alias(alias_type) => alias_type.referenced_type.clone(),
958            _ => return Err(self.create_err(ErrorKind::UnknownSymbol, &type_name_to_find.name.0)),
959        };
960
961        Ok(result_type)
962    }
963
964    /*
965        fn analyze_named_type(
966        &self,
967        type_name_to_find: &QualifiedTypeIdentifier,
968    ) -> Result<Type, Error> {
969        let (path, text) = self.get_path(type_name_to_find);
970
971        let resolved_type = if let Some(found) = self.shared.lookup.get_struct(&path, &text) {
972            Type::Struct(found)
973        } else if let Some(found) = self.shared.lookup.get_enum(&path, &text) {
974            Type::Enum(found)
975        } else if let Some(found) = self.shared.lookup.get_rust_type(&path, &text) {
976            Type::RustType(found)
977        } else {
978            Err(self.create_err(
979                ErrorKind::UnknownTypeReference,
980                &type_name_to_find.name.0,
981            ))?
982        };
983
984        Ok(resolved_type)
985    }
986     */
987
988    fn create_default_value_for_type(
989        &mut self,
990        node: &swamp_script_ast::Node,
991        field_type: &Type,
992    ) -> Result<Expression, Error> {
993        let kind = match field_type {
994            Type::Bool => ExpressionKind::Literal(Literal::BoolLiteral(false)),
995            Type::Int => ExpressionKind::Literal(Literal::IntLiteral(0)),
996            Type::Float => ExpressionKind::Literal(Literal::FloatLiteral(Fp::zero())),
997            Type::String => ExpressionKind::Literal(Literal::StringLiteral(String::new())),
998            Type::Array(array_type_ref) => {
999                ExpressionKind::Literal(Literal::Array(array_type_ref.clone(), vec![]))
1000            }
1001            Type::Tuple(tuple_type_ref) => {
1002                let mut expressions = Vec::new();
1003                for resolved_type in &tuple_type_ref.0 {
1004                    let expr = self.create_default_value_for_type(node, resolved_type)?;
1005                    expressions.push(expr);
1006                }
1007                ExpressionKind::Literal(Literal::TupleLiteral(tuple_type_ref.clone(), expressions))
1008            }
1009            Type::Map(map_type_ref) => {
1010                ExpressionKind::Literal(Literal::Map(map_type_ref.clone(), vec![]))
1011            }
1012            Type::Optional(_optional_type) => ExpressionKind::Literal(Literal::NoneLiteral),
1013
1014            Type::Struct(struct_ref) => self.create_default_static_call(node, struct_ref)?,
1015            _ => {
1016                return Err(
1017                    self.create_err(ErrorKind::NoDefaultImplemented(field_type.clone()), node)
1018                );
1019            }
1020        };
1021
1022        let expr = self.create_expr(kind, field_type.clone(), node);
1023        Ok(expr)
1024    }
1025
1026    fn create_default_static_call(
1027        &mut self,
1028        node: &swamp_script_ast::Node,
1029        struct_ref_borrow: &StructTypeRef,
1030    ) -> Result<ExpressionKind, Error> {
1031        struct_ref_borrow
1032            .borrow()
1033            .functions
1034            .get(&"default".to_string())
1035            .map_or_else(
1036                || {
1037                    Err(self.create_err(
1038                        ErrorKind::NoDefaultImplementedForStruct(struct_ref_borrow.clone()),
1039                        node,
1040                    ))
1041                },
1042                |function| {
1043                    let kind = match &**function {
1044                        Function::Internal(internal_function) => {
1045                            ExpressionKind::InternalFunctionAccess(internal_function.clone())
1046                        }
1047                        Function::External(external_function) => {
1048                            ExpressionKind::ExternalFunctionAccess(external_function.clone())
1049                        }
1050                    };
1051
1052                    let base_expr =
1053                        self.create_expr(kind, Type::Function(function.signature().clone()), node);
1054
1055                    let empty_call_postfix = Postfix {
1056                        node: self.to_node(node),
1057                        ty: *function.signature().return_type.clone(),
1058                        kind: PostfixKind::FunctionCall(vec![]),
1059                    };
1060
1061                    let kind =
1062                        ExpressionKind::PostfixChain(Box::new(base_expr), vec![empty_call_postfix]);
1063
1064                    Ok(kind)
1065                },
1066            )
1067    }
1068
1069    fn add_postfix(
1070        &mut self,
1071        vec: &mut Vec<Postfix>,
1072        kind: PostfixKind,
1073        ty: Type,
1074        node: &swamp_script_ast::Node,
1075    ) {
1076        let resolved_node = self.to_node(node);
1077        let postfix = Postfix {
1078            node: resolved_node,
1079            ty,
1080            kind,
1081        };
1082
1083        vec.push(postfix);
1084    }
1085
1086    /// # Panics
1087    ///
1088    /// # Errors
1089    ///
1090    pub fn analyze_struct_field(
1091        &mut self,
1092        field_name: &swamp_script_ast::Node,
1093        tv: Type,
1094    ) -> Result<(StructTypeRef, usize, Type), Error> {
1095        let field_name_str = self.get_text(field_name).to_string();
1096
1097        if let Type::Struct(struct_type) = &tv {
1098            if let Some(found_field) = struct_type
1099                .borrow()
1100                .anon_struct_type
1101                .defined_fields
1102                .get(&field_name_str)
1103            {
1104                let index = struct_type
1105                    .borrow()
1106                    .anon_struct_type
1107                    .defined_fields
1108                    .get_index(&field_name_str)
1109                    .expect("checked earlier");
1110
1111                return Ok((struct_type.clone(), index, found_field.field_type.clone()));
1112            }
1113        }
1114
1115        Err(self.create_err(ErrorKind::UnknownStructField, field_name))
1116    }
1117
1118    #[allow(clippy::too_many_lines)]
1119    fn analyze_postfix_chain(
1120        &mut self,
1121        chain: &swamp_script_ast::PostfixChain,
1122    ) -> Result<Expression, Error> {
1123        if let swamp_script_ast::ExpressionKind::StaticMemberFunctionReference(
1124            qualified_type_reference,
1125            member_name,
1126        ) = &chain.base.kind
1127        {
1128            if let Some(found_expr) =
1129                self.check_for_internal_static_call(qualified_type_reference, member_name, &[])?
1130            {
1131                return Ok(found_expr);
1132            }
1133        }
1134
1135        let (start, is_mutable) =
1136            self.analyze_start_chain_expression_get_mutability(&chain.base, None)?;
1137
1138        let mut tv = TypeWithMut {
1139            resolved_type: start.ty.clone(),
1140            is_mutable,
1141        };
1142
1143        let mut uncertain = false;
1144
1145        let mut suffixes = Vec::new();
1146
1147        for item in &chain.postfixes {
1148            match item {
1149                swamp_script_ast::Postfix::FieldAccess(field_name) => {
1150                    let (struct_type_ref, index, return_type) =
1151                        self.analyze_struct_field(&field_name.clone(), tv.resolved_type)?;
1152                    self.add_postfix(
1153                        &mut suffixes,
1154                        PostfixKind::StructField(struct_type_ref.clone(), index),
1155                        return_type.clone(),
1156                        field_name,
1157                    );
1158
1159                    tv.resolved_type = return_type.clone();
1160                    // keep previous `is_mutable`
1161                }
1162                swamp_script_ast::Postfix::MemberCall(member_name, ast_arguments) => {
1163                    let dereference = ast_arguments
1164                        .iter()
1165                        .map(|x| &x.expression)
1166                        .collect::<Vec<_>>();
1167                    if let Some(found_internal) = self.check_for_internal_member_call(
1168                        &tv.resolved_type,
1169                        tv.is_mutable,
1170                        member_name,
1171                        &dereference,
1172                    )? {
1173                        tv.resolved_type = found_internal.ty.clone();
1174                        tv.is_mutable = false;
1175                        suffixes.push(found_internal);
1176                    } else if let Type::Struct(struct_type) = &tv.resolved_type.clone() {
1177                        let return_type = self.analyze_postfix_member_call(
1178                            struct_type,
1179                            tv.is_mutable,
1180                            member_name,
1181                            ast_arguments,
1182                            &mut suffixes,
1183                        )?;
1184
1185                        //self.add_postfix(&mut suffixes, kind, return_type.clone(), member_name);
1186                        tv.resolved_type = return_type.clone();
1187                        tv.is_mutable = false;
1188                    } else {
1189                        return Err(
1190                            self.create_err(ErrorKind::NotValidLocationStartingPoint, member_name)
1191                        );
1192                    }
1193                }
1194                swamp_script_ast::Postfix::FunctionCall(node, arguments) => {
1195                    if let Type::Function(signature) = &tv.resolved_type {
1196                        let resolved_node = self.to_node(node);
1197                        let resolved_arguments = self.analyze_and_verify_parameters(
1198                            &resolved_node,
1199                            &signature.parameters,
1200                            arguments,
1201                        )?;
1202                        self.add_postfix(
1203                            &mut suffixes,
1204                            PostfixKind::FunctionCall(resolved_arguments),
1205                            *signature.return_type.clone(),
1206                            node,
1207                        );
1208
1209                        tv.resolved_type = *signature.return_type.clone();
1210                        tv.is_mutable = false;
1211                    };
1212                }
1213
1214                swamp_script_ast::Postfix::Subscript(index_expr) => {
1215                    let collection_type = tv.resolved_type.clone();
1216                    match &collection_type {
1217                        Type::String => {
1218                            if let swamp_script_ast::ExpressionKind::Range(min, max, mode) =
1219                                &index_expr.kind
1220                            {
1221                                let range = self.analyze_range(min, max, mode)?;
1222
1223                                self.add_postfix(
1224                                    &mut suffixes,
1225                                    PostfixKind::StringRangeIndex(range),
1226                                    collection_type.clone(),
1227                                    &index_expr.node,
1228                                );
1229
1230                                tv.resolved_type = Type::String;
1231                            } else {
1232                                let int_argument_context = TypeContext::new_argument(&Type::Int);
1233                                let resolved_index_expr =
1234                                    self.analyze_expression(index_expr, &int_argument_context)?;
1235                                self.add_postfix(
1236                                    &mut suffixes,
1237                                    PostfixKind::StringIndex(resolved_index_expr),
1238                                    Type::String,
1239                                    &index_expr.node,
1240                                );
1241                            }
1242                            tv.resolved_type = Type::String;
1243                            tv.is_mutable = false;
1244                        }
1245
1246                        Type::Array(array_type_ref) => {
1247                            if let swamp_script_ast::ExpressionKind::Range(
1248                                min_expr,
1249                                max_expr,
1250                                mode,
1251                            ) = &index_expr.kind
1252                            {
1253                                let range = self.analyze_range(min_expr, max_expr, mode)?;
1254
1255                                self.add_postfix(
1256                                    &mut suffixes,
1257                                    PostfixKind::ArrayRangeIndex(array_type_ref.clone(), range),
1258                                    collection_type.clone(),
1259                                    &index_expr.node,
1260                                );
1261
1262                                tv.resolved_type = collection_type.clone();
1263                            } else {
1264                                let int_argument_context = TypeContext::new_argument(&Type::Int);
1265                                let resolved_index_expr =
1266                                    self.analyze_expression(index_expr, &int_argument_context)?;
1267                                self.add_postfix(
1268                                    &mut suffixes,
1269                                    PostfixKind::ArrayIndex(
1270                                        array_type_ref.clone(),
1271                                        resolved_index_expr,
1272                                    ),
1273                                    array_type_ref.item_type.clone(),
1274                                    &index_expr.node,
1275                                );
1276
1277                                tv.resolved_type = array_type_ref.item_type.clone();
1278                            }
1279
1280                            tv.is_mutable = false;
1281                        }
1282
1283                        Type::Map(map_type_ref) => {
1284                            let key_type_context =
1285                                TypeContext::new_argument(&map_type_ref.key_type);
1286                            let resolved_key_expr =
1287                                self.analyze_expression(index_expr, &key_type_context)?;
1288                            let return_type =
1289                                Type::Optional(Box::from(map_type_ref.value_type.clone()));
1290                            self.add_postfix(
1291                                &mut suffixes,
1292                                PostfixKind::MapIndex(map_type_ref.clone(), resolved_key_expr),
1293                                return_type.clone(),
1294                                &index_expr.node,
1295                            );
1296
1297                            tv.resolved_type = return_type;
1298                            tv.is_mutable = false;
1299                        }
1300
1301                        Type::Generic(base, generic_type_parameters) => match &**base {
1302                            Type::External(found_rust_type) => {
1303                                if found_rust_type.number == SPARSE_TYPE_ID {
1304                                    let sparse_id = self
1305                                        .shared
1306                                        .lookup_table
1307                                        .get_external_type("SparseId")
1308                                        .expect("SparseId is missing");
1309                                    let binding = Type::External(sparse_id.clone());
1310                                    let sparse_id_context = TypeContext::new_argument(&binding);
1311                                    let contained_type = &generic_type_parameters[0];
1312                                    let resolved_key =
1313                                        self.analyze_expression(index_expr, &sparse_id_context)?;
1314
1315                                    let return_type =
1316                                        Type::Optional(Box::new(contained_type.clone()));
1317
1318                                    self.add_postfix(
1319                                        &mut suffixes,
1320                                        PostfixKind::ExternalTypeIndexRef(
1321                                            found_rust_type.clone(),
1322                                            resolved_key,
1323                                        ),
1324                                        return_type.clone(),
1325                                        &index_expr.node,
1326                                    );
1327
1328                                    tv.resolved_type = return_type;
1329                                    tv.is_mutable = false;
1330                                } else {
1331                                    panic!("unknown generic type lookup")
1332                                }
1333                            }
1334                            _ => panic!("not supported"),
1335                        },
1336                        _ => {
1337                            return Err(self.create_err(
1338                                ErrorKind::ExpectedArray(collection_type),
1339                                &index_expr.node,
1340                            ));
1341                        }
1342                    }
1343                }
1344
1345                swamp_script_ast::Postfix::NoneCoalesce(default_expr) => {
1346                    let unwrapped_type = if let Type::Optional(unwrapped_type) = &tv.resolved_type {
1347                        unwrapped_type
1348                    } else if uncertain {
1349                        &tv.resolved_type
1350                    } else {
1351                        return Err(
1352                            self.create_err(ErrorKind::CanNotNoneCoalesce, &default_expr.node)
1353                        );
1354                    };
1355
1356                    let unwrapped_type_context = TypeContext::new_argument(unwrapped_type);
1357                    let resolved_default_expr =
1358                        self.analyze_expression(default_expr, &unwrapped_type_context)?;
1359                    self.add_postfix(
1360                        &mut suffixes,
1361                        PostfixKind::NoneCoalesce(resolved_default_expr),
1362                        unwrapped_type.clone(),
1363                        &default_expr.node,
1364                    );
1365                    tv.resolved_type = unwrapped_type.clone();
1366                    uncertain = false; // the chain is safe, because this will always solve None
1367                }
1368
1369                swamp_script_ast::Postfix::OptionUnwrap(option_node) => {
1370                    if let Type::Optional(unwrapped_type) = &tv.resolved_type {
1371                        uncertain = true;
1372                        self.add_postfix(
1373                            &mut suffixes,
1374                            PostfixKind::OptionUnwrap,
1375                            *unwrapped_type.clone(),
1376                            option_node,
1377                        );
1378                        tv.resolved_type = *unwrapped_type.clone();
1379                    } else {
1380                        return Err(self.create_err(ErrorKind::ExpectedOptional, option_node));
1381                    }
1382                }
1383            }
1384        }
1385
1386        if uncertain {
1387            if let Type::Optional(_) = tv.resolved_type {
1388            } else {
1389                tv.resolved_type = Type::Optional(Box::from(tv.resolved_type.clone()));
1390            }
1391        }
1392
1393        Ok(self.create_expr(
1394            ExpressionKind::PostfixChain(Box::new(start), suffixes),
1395            tv.resolved_type,
1396            &chain.base.node,
1397        ))
1398    }
1399
1400    fn analyze_bool_argument_expression(
1401        &mut self,
1402        expression: &swamp_script_ast::Expression,
1403    ) -> Result<BooleanExpression, Error> {
1404        let bool_context = TypeContext::new_argument(&Type::Bool);
1405        let resolved_expression = self.analyze_expression(expression, &bool_context)?;
1406        let expr_type = resolved_expression.ty.clone();
1407
1408        let bool_expression = match expr_type {
1409            Type::Bool => resolved_expression,
1410            Type::Optional(_) => self.create_expr(
1411                ExpressionKind::CoerceOptionToBool(Box::new(resolved_expression)),
1412                Type::Bool,
1413                &expression.node,
1414            ),
1415            _ => {
1416                return Err(self.create_err(ErrorKind::ExpectedBooleanExpression, &expression.node));
1417            }
1418        };
1419
1420        Ok(BooleanExpression {
1421            expression: Box::from(bool_expression),
1422        })
1423    }
1424
1425    fn analyze_iterable(
1426        &mut self,
1427        force_mut: Option<swamp_script_ast::Node>,
1428        expression: &swamp_script_ast::MutableOrImmutableExpression,
1429    ) -> Result<Iterable, Error> {
1430        let any_context = TypeContext::new_anything_argument();
1431        let resolved_expression: MutOrImmutableExpression = if force_mut.is_some() {
1432            let resolved_node = self.to_node(&force_mut.unwrap());
1433            MutOrImmutableExpression {
1434                expression_or_location: ArgumentExpressionOrLocation::Location(
1435                    self.analyze_to_location(
1436                        &expression.expression,
1437                        &any_context,
1438                        LocationSide::Rhs,
1439                    )?,
1440                ),
1441                is_mutable: Some(resolved_node),
1442            }
1443        } else {
1444            self.analyze_mut_or_immutable_expression(expression, &any_context, LocationSide::Rhs)?
1445        };
1446
1447        let resolved_type = &resolved_expression.ty().clone();
1448        let (key_type, value_type): (Option<Type>, Type) = match resolved_type {
1449            Type::Array(array_type) => (Some(Type::Int), array_type.item_type.clone()),
1450            Type::Map(map_type_ref) => (
1451                Some(map_type_ref.key_type.clone()),
1452                map_type_ref.value_type.clone(),
1453            ),
1454            Type::String => (Some(Type::Int), Type::String),
1455            Type::Iterable(item_type) => (None, *item_type.clone()),
1456            Type::Generic(_base_type, params) => {
1457                // TODO: HACK: We assume it is a container that iterates over the type parameters
1458                // TODO: HACK: We assume that it is a sparse map
1459                // TODO: HACK: Remove hardcoded number
1460                let rust_type_ref_for_id = self
1461                    .shared
1462                    .lookup_table
1463                    .get_external_type("SparseId")
1464                    .expect("SparseId was missing");
1465                let rust_id_type = Type::External(rust_type_ref_for_id.clone());
1466                (Some(rust_id_type), params[0].clone())
1467            }
1468            _ => return Err(self.create_err(ErrorKind::NotAnIterator, &expression.expression.node)),
1469        };
1470
1471        Ok(Iterable {
1472            key_type,
1473            value_type,
1474            resolved_expression: Box::new(resolved_expression),
1475        })
1476    }
1477
1478    fn analyze_argument_expressions(
1479        &mut self,
1480        expected_type: Option<&Type>,
1481        ast_expressions: &[swamp_script_ast::Expression],
1482    ) -> Result<Vec<Expression>, Error> {
1483        let mut resolved_expressions = Vec::new();
1484        let argument_expressions_context = TypeContext::new_unsure_argument(expected_type);
1485        for expression in ast_expressions {
1486            resolved_expressions
1487                .push(self.analyze_expression(expression, &argument_expressions_context)?);
1488        }
1489        Ok(resolved_expressions)
1490    }
1491
1492    fn analyze_block(
1493        &mut self,
1494        _node: &swamp_script_ast::Node,
1495        context: &TypeContext,
1496        ast_expressions: &[swamp_script_ast::Expression],
1497    ) -> Result<(Vec<Expression>, Type), Error> {
1498        if ast_expressions.is_empty() {
1499            return Ok((vec![], Type::Unit));
1500        }
1501
1502        self.push_block_scope("block");
1503
1504        let mut resolved_expressions = Vec::with_capacity(ast_expressions.len());
1505
1506        for expression in &ast_expressions[..ast_expressions.len() - 1] {
1507            let stmt_context = context.with_expected_type(Some(&Type::Unit));
1508            let expr = self.analyze_expression(expression, &stmt_context)?;
1509
1510            if matches!(expr.ty, Type::Never) {
1511                resolved_expressions.push(expr);
1512                return Ok((resolved_expressions, Type::Never));
1513            }
1514
1515            resolved_expressions.push(expr);
1516        }
1517
1518        // Process the last expression - it determines the block's type
1519        let last_expr =
1520            self.analyze_expression(&ast_expressions[ast_expressions.len() - 1], context)?;
1521        let last_type = last_expr.ty.clone();
1522        resolved_expressions.push(last_expr);
1523
1524        self.pop_block_scope("block");
1525
1526        Ok((resolved_expressions, last_type))
1527    }
1528
1529    fn analyze_interpolated_string(
1530        &mut self,
1531        string_parts: &[swamp_script_ast::StringPart],
1532    ) -> Result<Vec<StringPart>, Error> {
1533        let mut resolved_parts = Vec::new();
1534        for part in string_parts {
1535            let resolved_string_part = match part {
1536                swamp_script_ast::StringPart::Literal(string_node, processed_string) => {
1537                    StringPart::Literal(self.to_node(string_node), processed_string.to_string())
1538                }
1539                swamp_script_ast::StringPart::Interpolation(expression, format_specifier) => {
1540                    let any_context = TypeContext::new_anything_argument();
1541                    let expr = self.analyze_expression(expression, &any_context)?;
1542                    let resolved_format_specifier =
1543                        self.analyze_format_specifier(Option::from(format_specifier));
1544                    StringPart::Interpolation(expr, resolved_format_specifier)
1545                }
1546            };
1547
1548            resolved_parts.push(resolved_string_part);
1549        }
1550
1551        Ok(resolved_parts)
1552    }
1553
1554    pub(crate) fn analyze_static_function_access(
1555        &self,
1556        qualified_func_name: &swamp_script_ast::QualifiedIdentifier,
1557    ) -> Result<Expression, Error> {
1558        let path = self.get_module_path(qualified_func_name.module_path.as_ref());
1559        let function_name = self.get_text(&qualified_func_name.name);
1560
1561        if let Some(found_table) = self.shared.get_symbol_table(&path) {
1562            if let Some(found_func) = found_table.get_function(function_name) {
1563                let (kind, return_type) = match found_func {
1564                    FuncDef::Internal(internal_fn) => (
1565                        ExpressionKind::InternalFunctionAccess(internal_fn.clone()),
1566                        &internal_fn.signature.return_type,
1567                    ),
1568                    FuncDef::External(external_fn) => (
1569                        ExpressionKind::ExternalFunctionAccess(external_fn.clone()),
1570                        &external_fn.signature.return_type,
1571                    ),
1572                    // Can not have a reference to an intrinsic function
1573                    FuncDef::Intrinsic(_) => {
1574                        return Err(
1575                            self.create_err(ErrorKind::UnknownFunction, &qualified_func_name.name)
1576                        );
1577                    }
1578                };
1579
1580                return Ok(self.create_expr(kind, *return_type.clone(), &qualified_func_name.name));
1581            }
1582        }
1583        Err(self.create_err(ErrorKind::UnknownFunction, &qualified_func_name.name))
1584    }
1585
1586    // The ast assumes it is something similar to a variable, but it can be a function reference as well.
1587    fn analyze_identifier_reference(
1588        &self,
1589        var_node: &swamp_script_ast::Node,
1590    ) -> Result<Expression, Error> {
1591        let text = self.get_text(var_node);
1592
1593        // Must check variable first, since that is more intuitive for the user.
1594        // local variables before other functions
1595        if let Some(found_variable) = self.try_find_variable(var_node) {
1596            return Ok(self.create_expr(
1597                ExpressionKind::VariableAccess(found_variable.clone()),
1598                found_variable.resolved_type.clone(),
1599                var_node,
1600            ));
1601        }
1602
1603        if let Some(found_symbol) = self.shared.lookup_table.get_symbol(text) {
1604            let expr = match found_symbol {
1605                Symbol::FunctionDefinition(func) => match func {
1606                    FuncDef::External(found_external_function) => self.create_expr(
1607                        ExpressionKind::ExternalFunctionAccess(found_external_function.clone()),
1608                        Type::Function(found_external_function.signature.clone()),
1609                        var_node,
1610                    ),
1611                    FuncDef::Internal(found_internal_function) => self.create_expr(
1612                        ExpressionKind::InternalFunctionAccess(found_internal_function.clone()),
1613                        Type::Function(found_internal_function.signature.clone()),
1614                        var_node,
1615                    ),
1616                    FuncDef::Intrinsic(_) => todo!(),
1617                },
1618
1619                _ => {
1620                    return Err(self.create_err(ErrorKind::UnknownIdentifier, var_node));
1621                }
1622            };
1623            return Ok(expr);
1624        }
1625
1626        Err(self.create_err(ErrorKind::UnknownIdentifier, var_node))
1627    }
1628    fn analyze_usize_index(
1629        &mut self,
1630        usize_expression: &swamp_script_ast::Expression,
1631    ) -> Result<Expression, Error> {
1632        let int_context = TypeContext::new_argument(&Type::Int);
1633        let lookup_expression = self.analyze_expression(usize_expression, &int_context)?;
1634        let lookup_resolution = lookup_expression.ty.clone();
1635
1636        match &lookup_resolution {
1637            Type::Int => {}
1638            _ => Err(self.create_err(
1639                ErrorKind::ArrayIndexMustBeInt(lookup_resolution),
1640                &usize_expression.node,
1641            ))?,
1642        }
1643
1644        Ok(lookup_expression)
1645    }
1646
1647    fn analyze_array_type_helper(
1648        &mut self,
1649        node: &swamp_script_ast::Node,
1650        items: &[swamp_script_ast::Expression],
1651        expected_type: Option<&Type>,
1652    ) -> Result<(ArrayTypeRef, Vec<Expression>), Error> {
1653        let expressions = self.analyze_argument_expressions(None, items)?;
1654        let item_type = if expressions.is_empty() {
1655            if let Some(found_expected_type) = expected_type {
1656                info!(?found_expected_type, "found array type");
1657                if let Type::Array(found) = found_expected_type {
1658                    found.item_type.clone()
1659                } else {
1660                    return Err(self.create_err(ErrorKind::NotAnArray, node));
1661                }
1662            } else {
1663                return Err(self.create_err(ErrorKind::NotAnArray, node));
1664            }
1665        } else {
1666            expressions[0].ty.clone()
1667        };
1668
1669        let array_type = ArrayType { item_type };
1670
1671        let array_type_ref = Rc::new(array_type);
1672
1673        Ok((array_type_ref, expressions))
1674    }
1675
1676    fn push_block_scope(&mut self, _debug_str: &str) {
1677        self.scope.block_scope_stack.push(BlockScope {
1678            mode: BlockScopeMode::Open,
1679            variables: SeqMap::default(),
1680        });
1681    }
1682
1683    fn pop_block_scope(&mut self, _debug_str: &str) {
1684        self.scope.block_scope_stack.pop();
1685    }
1686
1687    fn push_closed_block_scope(&mut self) {
1688        self.scope.block_scope_stack.push(BlockScope {
1689            mode: BlockScopeMode::Closed,
1690            variables: SeqMap::default(),
1691        });
1692    }
1693
1694    fn pop_closed_block_scope(&mut self) {
1695        self.scope.block_scope_stack.pop();
1696    }
1697
1698    fn analyze_enum_variant_ref(
1699        &self,
1700        qualified_type_identifier: &swamp_script_ast::QualifiedTypeIdentifier,
1701        variant_name: &swamp_script_ast::LocalTypeIdentifier,
1702    ) -> Result<EnumVariantTypeRef, Error> {
1703        let variant_name_string = self.get_text(&variant_name.0).to_string();
1704        self.get_enum_variant_type(qualified_type_identifier, &variant_name_string)
1705    }
1706
1707    fn analyze_match(
1708        &mut self,
1709        scrutinee: &swamp_script_ast::MutableOrImmutableExpression,
1710        default_context: &TypeContext,
1711        arms: &Vec<swamp_script_ast::MatchArm>,
1712    ) -> Result<(Match, Type), Error> {
1713        let mut known_type = default_context.expected_type.cloned();
1714        let own_context = default_context.clone();
1715        // Analyze the scrutinee with no specific expected type
1716        let scrutinee_context = TypeContext::new_anything_argument();
1717        let resolved_scrutinee = self.analyze_mut_or_immutable_expression(
1718            scrutinee,
1719            &scrutinee_context,
1720            LocationSide::Rhs,
1721        )?;
1722        let scrutinee_type = resolved_scrutinee.ty().clone();
1723
1724        // Ensure we have at least one arm
1725        if arms.is_empty() {
1726            return Err(self.create_err(ErrorKind::EmptyMatch, &scrutinee.expression.node));
1727        }
1728
1729        let mut resolved_arms = Vec::with_capacity(arms.len());
1730
1731        for arm in arms {
1732            let (resolved_arm, _anyone_wants_mutable) = self.analyze_arm(
1733                arm,
1734                &resolved_scrutinee,
1735                &own_context.with_expected_type(known_type.as_ref()),
1736                &scrutinee_type,
1737            )?;
1738
1739            if known_type.is_none() && !matches!(resolved_arm.expression.ty, Type::Never) {
1740                known_type = Some(resolved_arm.expression.ty.clone());
1741            }
1742            resolved_arms.push(resolved_arm);
1743        }
1744
1745        known_type.map_or_else(
1746            || {
1747                Err(self.create_err(
1748                    ErrorKind::MatchArmsMustHaveTypes,
1749                    &scrutinee.expression.node,
1750                ))
1751            },
1752            |encountered_type| {
1753                if matches!(encountered_type, Type::Never) {
1754                    Err(self.create_err(
1755                        ErrorKind::IncompatibleTypes(encountered_type.clone(), encountered_type),
1756                        &scrutinee.expression.node,
1757                    ))
1758                } else {
1759                    Ok((
1760                        Match {
1761                            expression: Box::new(resolved_scrutinee),
1762                            arms: resolved_arms,
1763                        },
1764                        encountered_type,
1765                    ))
1766                }
1767            },
1768        )
1769    }
1770
1771    fn analyze_arm(
1772        &mut self,
1773        arm: &swamp_script_ast::MatchArm,
1774        _expression: &MutOrImmutableExpression,
1775        type_context: &TypeContext,
1776        expected_condition_type: &Type,
1777    ) -> Result<(MatchArm, bool), Error> {
1778        let (resolved_pattern, scope_was_pushed, anyone_wants_mutable) =
1779            self.analyze_pattern(&arm.pattern, expected_condition_type)?;
1780
1781        let resolved_expression = self.analyze_expression(&arm.expression, type_context)?;
1782        if scope_was_pushed {
1783            self.pop_block_scope("analyze_arm");
1784        }
1785
1786        let resolved_type = resolved_expression.ty.clone();
1787
1788        Ok((
1789            MatchArm {
1790                pattern: resolved_pattern,
1791                expression: Box::from(resolved_expression),
1792                expression_type: resolved_type,
1793            },
1794            anyone_wants_mutable,
1795        ))
1796    }
1797
1798    fn str_to_int(text: &str) -> Result<i32, ParseIntError> {
1799        text.parse::<i32>()
1800    }
1801
1802    fn str_to_float(text: &str) -> Result<f32, ParseFloatError> {
1803        text.parse::<f32>()
1804    }
1805
1806    fn analyze_pattern_literal(
1807        &mut self,
1808        node: &swamp_script_ast::Node,
1809        ast_literal: &swamp_script_ast::LiteralKind,
1810        expected_condition_type: &Type,
1811    ) -> Result<NormalPattern, Error> {
1812        let required_condition_type_context = TypeContext::new_argument(expected_condition_type);
1813        let (resolved_literal, literal_type) =
1814            self.analyze_literal(node, ast_literal, &required_condition_type_context)?;
1815
1816        if !literal_type.compatible_with(expected_condition_type) {
1817            return Err(self.create_err(
1818                ErrorKind::IncompatibleTypes(literal_type, expected_condition_type.clone()),
1819                node,
1820            ));
1821        }
1822
1823        Ok(NormalPattern::Literal(resolved_literal))
1824    }
1825
1826    const fn to_node(&self, node: &swamp_script_ast::Node) -> Node {
1827        Node {
1828            span: Span {
1829                file_id: self.shared.file_id,
1830                offset: node.span.offset,
1831                length: node.span.length,
1832            },
1833        }
1834    }
1835
1836    fn get_module_path(&self, module_path: Option<&swamp_script_ast::ModulePath>) -> Vec<String> {
1837        module_path.as_ref().map_or_else(Vec::new, |found| {
1838            let mut strings = Vec::new();
1839            for path_item in &found.0 {
1840                strings.push(self.get_text(path_item).to_string());
1841            }
1842            strings
1843        })
1844    }
1845
1846    fn get_enum_variant_type(
1847        &self,
1848        qualified_type_identifier: &swamp_script_ast::QualifiedTypeIdentifier,
1849        variant_name: &str,
1850    ) -> Result<EnumVariantTypeRef, Error> {
1851        let (symbol_table, enum_name) =
1852            self.get_symbol_table_and_name(qualified_type_identifier)?;
1853        symbol_table
1854            .get_enum_variant_type(&enum_name, variant_name)
1855            .ok_or_else(|| {
1856                self.create_err(
1857                    ErrorKind::UnknownEnumVariantType,
1858                    &qualified_type_identifier.name.0,
1859                )
1860            })
1861    }
1862
1863    pub(crate) fn get_symbol_table_and_name(
1864        &self,
1865        type_identifier: &swamp_script_ast::QualifiedTypeIdentifier,
1866    ) -> Result<(&SymbolTable, String), Error> {
1867        let path = self.get_module_path(type_identifier.module_path.as_ref());
1868        let name = self.get_text(&type_identifier.name.0).to_string();
1869
1870        let maybe_symbol_table = self.shared.get_symbol_table(&path);
1871        maybe_symbol_table.map_or_else(
1872            || Err(self.create_err(ErrorKind::UnknownModule, &type_identifier.name.0)),
1873            |symbol_table| Ok((symbol_table, name)),
1874        )
1875    }
1876
1877    const fn analyze_compound_operator(
1878        &self,
1879        ast_operator: &swamp_script_ast::CompoundOperator,
1880    ) -> CompoundOperator {
1881        let resolved_node = self.to_node(&ast_operator.node);
1882        let resolved_kind = match ast_operator.kind {
1883            swamp_script_ast::CompoundOperatorKind::Add => CompoundOperatorKind::Add,
1884            swamp_script_ast::CompoundOperatorKind::Sub => CompoundOperatorKind::Sub,
1885            swamp_script_ast::CompoundOperatorKind::Mul => CompoundOperatorKind::Mul,
1886            swamp_script_ast::CompoundOperatorKind::Div => CompoundOperatorKind::Div,
1887            swamp_script_ast::CompoundOperatorKind::Modulo => CompoundOperatorKind::Modulo,
1888        };
1889
1890        CompoundOperator {
1891            node: resolved_node,
1892            kind: resolved_kind,
1893        }
1894    }
1895
1896    const fn to_node_option(&self, maybe_node: Option<&swamp_script_ast::Node>) -> Option<Node> {
1897        match maybe_node {
1898            None => None,
1899            Some(node) => Some(self.to_node(node)),
1900        }
1901    }
1902
1903    const fn analyze_format_specifier(
1904        &self,
1905        ast_format_specifier: Option<&swamp_script_ast::FormatSpecifier>,
1906    ) -> Option<FormatSpecifier> {
1907        let f = match ast_format_specifier {
1908            None => return None,
1909            Some(ast_format) => match ast_format {
1910                swamp_script_ast::FormatSpecifier::LowerHex(node) => FormatSpecifier {
1911                    node: self.to_node(node),
1912                    kind: FormatSpecifierKind::LowerHex,
1913                },
1914                swamp_script_ast::FormatSpecifier::UpperHex(node) => FormatSpecifier {
1915                    node: self.to_node(node),
1916                    kind: FormatSpecifierKind::UpperHex,
1917                },
1918                swamp_script_ast::FormatSpecifier::Binary(node) => FormatSpecifier {
1919                    node: self.to_node(node),
1920                    kind: FormatSpecifierKind::Binary,
1921                },
1922                swamp_script_ast::FormatSpecifier::Float(node) => FormatSpecifier {
1923                    node: self.to_node(node),
1924                    kind: FormatSpecifierKind::Float,
1925                },
1926                swamp_script_ast::FormatSpecifier::Precision(value, node, x) => {
1927                    let (precision_type, precision_node) = match x {
1928                        swamp_script_ast::PrecisionType::Float(node) => {
1929                            (PrecisionType::Float, self.to_node(node))
1930                        }
1931                        swamp_script_ast::PrecisionType::String(node) => {
1932                            (PrecisionType::String, self.to_node(node))
1933                        }
1934                    };
1935                    FormatSpecifier {
1936                        node: self.to_node(node),
1937                        kind: FormatSpecifierKind::Precision(
1938                            *value,
1939                            precision_node,
1940                            precision_type,
1941                        ),
1942                    }
1943                }
1944            },
1945        };
1946
1947        Some(f)
1948    }
1949
1950    fn analyze_with_expr(
1951        &mut self,
1952        context: &TypeContext,
1953        variables: &[swamp_script_ast::VariableBinding],
1954        expression: &swamp_script_ast::Expression,
1955    ) -> Result<Expression, Error> {
1956        let mut variable_expressions = Vec::new();
1957
1958        for variable in variables {
1959            let any_context = TypeContext::new_anything_argument();
1960            let var = self.analyze_mut_or_immutable_expression(
1961                &variable.expression,
1962                &any_context,
1963                LocationSide::Rhs,
1964            )?;
1965            variable_expressions.push(var);
1966        }
1967
1968        self.push_closed_block_scope();
1969        let mut expressions = Vec::new();
1970        for (variable_binding, resolved_expression) in variables.iter().zip(variable_expressions) {
1971            let initialize_variable_expression = self.create_variable_binding_for_with(
1972                &variable_binding.variable,
1973                resolved_expression,
1974            )?;
1975            expressions.push(initialize_variable_expression);
1976        }
1977
1978        let resolved_expression = self.analyze_expression(expression, context)?;
1979        let block_type = resolved_expression.ty.clone();
1980        expressions.push(resolved_expression);
1981
1982        let block_expression_kind = ExpressionKind::Block(expressions);
1983        self.pop_closed_block_scope();
1984
1985        let block_expr = self.create_expr(block_expression_kind, block_type, &expression.node);
1986        Ok(block_expr)
1987    }
1988
1989    fn analyze_when_expr(
1990        &mut self,
1991        context: &TypeContext,
1992        variables: &[swamp_script_ast::WhenBinding],
1993        true_expr: &swamp_script_ast::Expression,
1994        else_expr: Option<&swamp_script_ast::Expression>,
1995    ) -> Result<Expression, Error> {
1996        // Since we are making new variable bindings, we have to push a scope for them
1997        self.push_block_scope("when");
1998        let mut bindings = Vec::new();
1999        for variable_binding in variables {
2000            let mut_expr = if let Some(found_expr) = &variable_binding.expression {
2001                let any_context = TypeContext::new_anything_argument();
2002                self.analyze_mut_or_immutable_expression(
2003                    found_expr,
2004                    &any_context,
2005                    LocationSide::Rhs,
2006                )?
2007            } else {
2008                let same_var = self.find_variable(&variable_binding.variable)?;
2009
2010                let is_mutable = same_var.mutable_node.clone();
2011                let argument_expression = if same_var.is_mutable() {
2012                    let loc = SingleLocationExpression {
2013                        kind: SingleLocationExpressionKind::MutVariableRef,
2014                        node: self.to_node(&variable_binding.variable.name),
2015                        ty: same_var.resolved_type.clone(),
2016                        starting_variable: same_var,
2017                        access_chain: vec![],
2018                    };
2019                    ArgumentExpressionOrLocation::Location(loc)
2020                } else {
2021                    let generated_expr_kind = ExpressionKind::VariableAccess(same_var.clone());
2022                    let generated_expression = self.create_expr(
2023                        generated_expr_kind,
2024                        same_var.resolved_type.clone(),
2025                        &variable_binding.variable.name,
2026                    );
2027                    ArgumentExpressionOrLocation::Expression(generated_expression)
2028                };
2029
2030                MutOrImmutableExpression {
2031                    expression_or_location: argument_expression,
2032                    is_mutable,
2033                }
2034            };
2035
2036            let ty = mut_expr.ty();
2037
2038            if let Type::Optional(found_ty) = ty {
2039                let variable_ref = self.create_variable(&variable_binding.variable, found_ty)?;
2040
2041                let binding = WhenBinding {
2042                    variable: variable_ref,
2043                    expr: mut_expr,
2044                };
2045                bindings.push(binding);
2046            } else {
2047                return Err(self.create_err(ErrorKind::ExpectedOptional, &true_expr.node));
2048            }
2049        }
2050
2051        let resolved_true = self.analyze_expression(true_expr, context)?;
2052        let block_type = resolved_true.ty.clone();
2053
2054        self.pop_block_scope("when");
2055
2056        let maybe_resolved_else = if let Some(found_else) = else_expr {
2057            let block_type_for_true_context = context.we_know_expected_type(&block_type);
2058            Some(Box::new(self.analyze_expression(
2059                found_else,
2060                &block_type_for_true_context,
2061            )?))
2062        } else {
2063            None
2064        };
2065
2066        let when_kind =
2067            ExpressionKind::When(bindings, Box::from(resolved_true), maybe_resolved_else);
2068
2069        let block_expr = self.create_expr(when_kind, block_type, &true_expr.node);
2070        Ok(block_expr)
2071    }
2072
2073    fn analyze_guard(
2074        &mut self,
2075        node: &swamp_script_ast::Node,
2076        context: &TypeContext,
2077        guard_expressions: &Vec<swamp_script_ast::GuardExpr>,
2078    ) -> Result<Expression, Error> {
2079        let mut guards = Vec::new();
2080        let mut found_wildcard = None;
2081        let mut detected_type = context.expected_type.cloned();
2082
2083        for guard in guard_expressions {
2084            let resolved_condition = match &guard.clause {
2085                swamp_script_ast::GuardClause::Wildcard(x) => {
2086                    if found_wildcard.is_some() {
2087                        return Err(
2088                            self.create_err(ErrorKind::GuardCanNotHaveMultipleWildcards, node)
2089                        );
2090                    }
2091                    found_wildcard = Some(x);
2092                    None
2093                }
2094                swamp_script_ast::GuardClause::Expression(clause_expr) => {
2095                    if found_wildcard.is_some() {
2096                        return Err(self.create_err(ErrorKind::WildcardMustBeLastInGuard, node));
2097                    }
2098                    Some(self.analyze_bool_argument_expression(clause_expr)?)
2099                }
2100            };
2101
2102            let resolved_result = self.analyze_expression(
2103                &guard.result,
2104                &context.with_expected_type(detected_type.as_ref()),
2105            )?;
2106            let ty = resolved_result.ty.clone();
2107            if detected_type.is_none() && !matches!(ty, Type::Never) {
2108                detected_type = Some(ty.clone());
2109            }
2110
2111            guards.push(Guard {
2112                condition: resolved_condition,
2113                result: resolved_result,
2114            });
2115        }
2116
2117        if found_wildcard.is_none() {
2118            return Err(self.create_err(ErrorKind::GuardMustHaveWildcard, node));
2119        }
2120
2121        let kind = ExpressionKind::Guard(guards);
2122
2123        detected_type.map_or_else(
2124            || Err(self.create_err(ErrorKind::GuardHasNoType, node)),
2125            |found_expecting_type| {
2126                let expr = self.create_expr(kind, found_expecting_type, node);
2127                Ok(expr)
2128            },
2129        )
2130    }
2131
2132    pub fn analyze_variable_assignment(
2133        &mut self,
2134        variable: &swamp_script_ast::Variable,
2135        source_expression: &swamp_script_ast::MutableOrImmutableExpression,
2136    ) -> Result<Expression, Error> {
2137        let any_argument_context = TypeContext::new_anything_argument();
2138        let source_expr = self.analyze_mut_or_immutable_expression(
2139            source_expression,
2140            &any_argument_context,
2141            LocationSide::Rhs,
2142        )?;
2143        let ty = source_expr.ty().clone();
2144        if !ty.is_concrete() {
2145            return Err(self.create_err(ErrorKind::VariableTypeMustBeConcrete, &variable.name));
2146        }
2147
2148        let maybe_found_variable = self.try_find_variable(&variable.name);
2149
2150        let kind: ExpressionKind = if let Some(found_var) = maybe_found_variable {
2151            if !found_var.is_mutable() {
2152                return Err(self.create_err(ErrorKind::VariableIsNotMutable, &variable.name));
2153            }
2154            if !found_var.resolved_type.assignable_type(&ty) {
2155                return Err(self.create_err(
2156                    ErrorKind::IncompatibleTypes(found_var.resolved_type.clone(), ty.clone()),
2157                    &variable.name,
2158                ));
2159            }
2160            ExpressionKind::VariableReassignment(found_var, Box::from(source_expr))
2161        } else {
2162            let new_var = self.create_variable(variable, &ty)?;
2163            ExpressionKind::VariableDefinition(new_var, Box::from(source_expr))
2164        };
2165
2166        Ok(self.create_expr(kind, Type::Unit, &variable.name))
2167    }
2168
2169    fn analyze_create_variable(
2170        &mut self,
2171        var: &swamp_script_ast::Variable,
2172        annotation_type: Option<&swamp_script_ast::Type>,
2173        source_expression: &swamp_script_ast::MutableOrImmutableExpression,
2174    ) -> Result<Expression, Error> {
2175        let ty = if let Some(found_ast_type) = annotation_type {
2176            Some(self.analyze_type(found_ast_type)?)
2177        } else {
2178            None
2179        };
2180
2181        let unsure_arg_context = TypeContext::new_unsure_argument(ty.as_ref());
2182
2183        let resolved_source = self.analyze_mut_or_immutable_expression(
2184            source_expression,
2185            &unsure_arg_context,
2186            LocationSide::Rhs,
2187        )?;
2188
2189        let var_ref = self.create_local_variable(
2190            &var.name,
2191            Option::from(&var.is_mutable),
2192            &resolved_source.ty(),
2193        )?;
2194
2195        let resolved_type = resolved_source.ty().clone();
2196        assert_ne!(resolved_type, Type::Unit);
2197        let kind = ExpressionKind::VariableDefinition(var_ref, Box::from(resolved_source));
2198
2199        let resolved_expr = self.create_expr(kind, Type::Unit, &var.name);
2200
2201        Ok(resolved_expr)
2202    }
2203
2204    fn add_location_item(
2205        &mut self,
2206        vec: &mut Vec<LocationAccess>,
2207        kind: LocationAccessKind,
2208        ty: Type,
2209        ast_node: &swamp_script_ast::Node,
2210    ) {
2211        let resolved_node = self.to_node(ast_node);
2212        let postfix = LocationAccess {
2213            node: resolved_node.clone(),
2214            ty,
2215            kind,
2216        };
2217
2218        vec.push(postfix);
2219    }
2220
2221    #[allow(clippy::too_many_lines)]
2222    fn analyze_chain_to_location(
2223        &mut self,
2224        chain: &swamp_script_ast::PostfixChain,
2225        context: &TypeContext,
2226        location_side: LocationSide,
2227    ) -> Result<SingleLocationExpression, Error> {
2228        let mut items = Vec::new();
2229
2230        let nothing_context =
2231            TypeContext::new(None, None, TypeContextScope::ArgumentOrOutsideFunction);
2232
2233        let base_expr = self.analyze_expression(&chain.base, &nothing_context)?;
2234        let ExpressionKind::VariableAccess(start_variable) = base_expr.kind else {
2235            return Err(self.create_err(ErrorKind::NotValidLocationStartingPoint, &chain.base.node));
2236        };
2237
2238        if !start_variable.is_mutable() {
2239            return Err(self.create_err(ErrorKind::VariableIsNotMutable, &chain.base.node));
2240        }
2241
2242        let mut ty = start_variable.resolved_type.clone();
2243        for (i, item) in chain.postfixes.iter().enumerate() {
2244            match &item {
2245                swamp_script_ast::Postfix::FieldAccess(field_name_node) => {
2246                    //let field_name_resolved = self.to_node(field_name_node)
2247                    let (struct_type_ref, index, return_type) =
2248                        self.analyze_struct_field(field_name_node, ty)?;
2249                    self.add_location_item(
2250                        &mut items,
2251                        LocationAccessKind::FieldIndex(struct_type_ref.clone(), index),
2252                        return_type.clone(),
2253                        field_name_node,
2254                    );
2255
2256                    ty = return_type.clone();
2257                }
2258                swamp_script_ast::Postfix::Subscript(lookup_expr) => {
2259                    let is_range = if let swamp_script_ast::ExpressionKind::Range(min, max, mode) =
2260                        &lookup_expr.kind
2261                    {
2262                        Some(self.analyze_range(min, max, mode)?)
2263                    } else {
2264                        None
2265                    };
2266                    match &ty {
2267                        Type::String => {
2268                            if let Some(range) = is_range {
2269                                self.add_location_item(
2270                                    &mut items,
2271                                    LocationAccessKind::StringRange(range),
2272                                    Type::String,
2273                                    &lookup_expr.node,
2274                                );
2275                            } else {
2276                                let index_expr_context = TypeContext::new_argument(&Type::Int);
2277                                let index_expr =
2278                                    self.analyze_expression(lookup_expr, &index_expr_context)?; // TODO: Support slice (range)
2279                                self.add_location_item(
2280                                    &mut items,
2281                                    LocationAccessKind::StringIndex(index_expr),
2282                                    Type::String,
2283                                    &lookup_expr.node,
2284                                );
2285                            }
2286                            ty = Type::String;
2287                        }
2288
2289                        Type::Array(array_type) => {
2290                            let int_argument_context = TypeContext::new_argument(&Type::Int);
2291                            let index_expr =
2292                                self.analyze_expression(lookup_expr, &int_argument_context)?; // TODO: Support slice (range)
2293                            self.add_location_item(
2294                                &mut items,
2295                                LocationAccessKind::ArrayIndex(array_type.clone(), index_expr),
2296                                array_type.item_type.clone(),
2297                                &lookup_expr.node,
2298                            );
2299                            ty = array_type.item_type.clone();
2300                        }
2301
2302                        Type::Map(map_type) => {
2303                            let key_type_argument_context =
2304                                TypeContext::new_argument(&map_type.key_type);
2305                            let key_expr =
2306                                self.analyze_expression(lookup_expr, &key_type_argument_context)?;
2307                            let is_last = i == chain.postfixes.len() - 1;
2308                            let allow_auto_insert = is_last && location_side == LocationSide::Lhs;
2309                            let (kind, lookup_type) = if allow_auto_insert {
2310                                // If this is the last postfix in the chain, then it is a "bare" access and auto-insert is allowed
2311                                // the type is `value_type` since this lookup is safe. we can create a memory location if there wasn't one
2312                                (
2313                                    LocationAccessKind::MapIndexInsertIfNonExisting(
2314                                        map_type.clone(),
2315                                        key_expr,
2316                                    ),
2317                                    map_type.value_type.clone(),
2318                                )
2319                            } else {
2320                                let optional_value_type =
2321                                    Type::Optional(Box::from(map_type.value_type.clone()));
2322                                (
2323                                    LocationAccessKind::MapIndex(map_type.clone(), key_expr),
2324                                    optional_value_type,
2325                                )
2326                            };
2327
2328                            self.add_location_item(
2329                                &mut items,
2330                                kind,
2331                                lookup_type.clone(),
2332                                &lookup_expr.node,
2333                            );
2334                            ty = lookup_type;
2335                        }
2336
2337                        Type::Generic(collection_type, generic_params) => {
2338                            if let Type::External(rust_type) = &**collection_type {
2339                                let val_type = generic_params[0].clone();
2340                                if rust_type.number == SPARSE_TYPE_ID {
2341                                    let sparse_id_type = self
2342                                        .shared
2343                                        .lookup_table
2344                                        .get_external_type("SparseId")
2345                                        .expect("should have SparseId");
2346
2347                                    let key_type = Type::External(sparse_id_type.clone());
2348                                    let key_type_context = TypeContext::new_argument(&key_type);
2349
2350                                    let key_expr =
2351                                        self.analyze_expression(lookup_expr, &key_type_context)?;
2352
2353                                    self.add_location_item(
2354                                        &mut items,
2355                                        LocationAccessKind::ExternalTypeIndex(
2356                                            rust_type.clone(),
2357                                            key_expr,
2358                                        ),
2359                                        key_type.clone(),
2360                                        &lookup_expr.node,
2361                                    );
2362
2363                                    ty = Type::Optional(Box::from(val_type.clone()));
2364                                }
2365                            }
2366                        }
2367
2368                        _ => {
2369                            return Err(
2370                                self.create_err(ErrorKind::IllegalIndexInChain, &lookup_expr.node)
2371                            );
2372                        }
2373                    }
2374                }
2375
2376                swamp_script_ast::Postfix::MemberCall(node, _) => {
2377                    return Err(self.create_err(ErrorKind::CallsCanNotBePartOfChain, node));
2378                }
2379
2380                swamp_script_ast::Postfix::FunctionCall(node, _) => {
2381                    return Err(self.create_err(ErrorKind::CallsCanNotBePartOfChain, node));
2382                }
2383                swamp_script_ast::Postfix::OptionUnwrap(node) => {
2384                    return Err(self.create_err(ErrorKind::UnwrapCanNotBePartOfChain, node));
2385                }
2386                swamp_script_ast::Postfix::NoneCoalesce(expr) => {
2387                    return Err(
2388                        self.create_err(ErrorKind::NoneCoalesceCanNotBePartOfChain, &expr.node)
2389                    );
2390                }
2391            }
2392        }
2393
2394        if let Some(found_expected_type) = context.expected_type {
2395            if !ty.compatible_with(found_expected_type) {
2396                return Err(self.create_err(
2397                    ErrorKind::IncompatibleTypes(ty, found_expected_type.clone()),
2398                    &chain.base.node,
2399                ));
2400            }
2401        }
2402
2403        let location = SingleLocationExpression {
2404            kind: SingleLocationExpressionKind::MutVariableRef,
2405            node: self.to_node(&chain.base.node),
2406            ty: ty.clone(),
2407            starting_variable: start_variable,
2408            access_chain: items,
2409        };
2410        Ok(location)
2411    }
2412
2413    fn analyze_to_location(
2414        &mut self,
2415        expr: &swamp_script_ast::Expression,
2416        context: &TypeContext,
2417        location_type: LocationSide,
2418    ) -> Result<SingleLocationExpression, Error> {
2419        //let resolved_expr = self.analyze_expression(expr, Some(&expected_type))?;
2420        match &expr.kind {
2421            swamp_script_ast::ExpressionKind::PostfixChain(chain) => {
2422                self.analyze_chain_to_location(chain, context, location_type)
2423            }
2424            swamp_script_ast::ExpressionKind::IdentifierReference(variable) => {
2425                let var = self.find_variable(variable)?;
2426                if var.is_mutable() {
2427                    Ok(SingleLocationExpression {
2428                        kind: SingleLocationExpressionKind::MutVariableRef,
2429                        node: self.to_node(&variable.name),
2430                        ty: var.resolved_type.clone(),
2431                        starting_variable: var,
2432                        access_chain: vec![],
2433                    })
2434                } else {
2435                    Err(self.create_err(ErrorKind::VariableIsNotMutable, &expr.node))
2436                }
2437            }
2438            _ => Err(self.create_err(ErrorKind::NotValidLocationStartingPoint, &expr.node)),
2439        }
2440    }
2441
2442    #[allow(clippy::single_match)]
2443    fn check_special_assignment_compound(
2444        &mut self,
2445        target_expression: &swamp_script_ast::Expression,
2446        target_type: &Type,
2447        op: &CompoundOperatorKind,
2448        source: &swamp_script_ast::Expression,
2449        source_type: &Type,
2450    ) -> Result<Option<ExpressionKind>, Error> {
2451        match &target_type {
2452            Type::Array(array_type) => {
2453                let target_type_context = TypeContext::new_argument(target_type);
2454                let source_type_context = TypeContext::new_argument(source_type);
2455                if *op == CompoundOperatorKind::Add
2456                    && source_type.compatible_with(&array_type.item_type)
2457                {
2458                    // Handle ArrayPush
2459                    let target_location = SingleMutLocationExpression(self.analyze_to_location(
2460                        target_expression,
2461                        &target_type_context,
2462                        LocationSide::Rhs,
2463                    )?);
2464                    let resolved_source = self.analyze_expression(source, &source_type_context)?;
2465                    return Ok(Option::from(ExpressionKind::IntrinsicCallMut(
2466                        IntrinsicFunction::VecSelfPush,
2467                        target_location,
2468                        vec![resolved_source],
2469                    )));
2470                } else if *op == CompoundOperatorKind::Add
2471                    && source_type.compatible_with(target_type)
2472                {
2473                    // Handle ArrayExtend
2474                    let target_location = SingleMutLocationExpression(self.analyze_to_location(
2475                        target_expression,
2476                        &target_type_context,
2477                        LocationSide::Rhs,
2478                    )?);
2479                    let resolved_source = self.analyze_expression(source, &source_type_context)?;
2480                    return Ok(Option::from(ExpressionKind::IntrinsicCallMut(
2481                        IntrinsicFunction::VecSelfExtend,
2482                        target_location,
2483                        vec![resolved_source],
2484                    )));
2485                }
2486            }
2487            _ => {}
2488        }
2489
2490        Ok(None)
2491    }
2492
2493    fn analyze_assignment_compound(
2494        &mut self,
2495        target_expression: &swamp_script_ast::Expression,
2496        ast_op: &swamp_script_ast::CompoundOperator,
2497        ast_source_expression: &swamp_script_ast::Expression,
2498    ) -> Result<Expression, Error> {
2499        let resolved_op = self.analyze_compound_operator(ast_op);
2500        let any_argument_context = TypeContext::new_anything_argument();
2501        let source_expr = self.analyze_expression(ast_source_expression, &any_argument_context)?;
2502        let source_expr_type_context = TypeContext::new_argument(&source_expr.ty);
2503
2504        let resolved_location = SingleMutLocationExpression(self.analyze_to_location(
2505            target_expression,
2506            &source_expr_type_context,
2507            LocationSide::Rhs,
2508        )?);
2509
2510        let kind = if let Some(found_special) = self.check_special_assignment_compound(
2511            target_expression,
2512            &resolved_location.0.ty,
2513            &resolved_op.kind,
2514            ast_source_expression,
2515            &source_expr.ty,
2516        )? {
2517            found_special
2518        } else {
2519            ExpressionKind::CompoundAssignment(
2520                resolved_location,
2521                resolved_op.kind,
2522                Box::from(source_expr),
2523            )
2524        };
2525
2526        let expr = self.create_expr(kind, Type::Unit, &target_expression.node);
2527
2528        Ok(expr)
2529    }
2530
2531    fn analyze_assignment(
2532        &mut self,
2533        target_location: &swamp_script_ast::Expression,
2534        ast_source_expression: &swamp_script_ast::Expression,
2535    ) -> Result<Expression, Error> {
2536        let any_argument_context = TypeContext::new_anything_argument();
2537        let resolved_location =
2538            self.analyze_to_location(target_location, &any_argument_context, LocationSide::Lhs)?;
2539
2540        let ty = resolved_location.ty.clone();
2541        if ty == Type::Unit {
2542            error!(?ast_source_expression, "unit problem");
2543        }
2544
2545        let lhs_argument_context = TypeContext::new_argument(&ty);
2546        let source_expr = self.analyze_expression(ast_source_expression, &lhs_argument_context)?;
2547
2548        let mut_location = SingleMutLocationExpression(resolved_location);
2549
2550        let kind = ExpressionKind::Assignment(Box::from(mut_location), Box::from(source_expr));
2551
2552        let expr = self.create_expr(kind, Type::Unit, &target_location.node); // Assignments are always of type Unit
2553
2554        Ok(expr)
2555    }
2556
2557    #[must_use]
2558    pub fn create_mut_single_location_expr(
2559        &self,
2560        kind: SingleLocationExpressionKind,
2561        ty: Type,
2562        ast_node: &swamp_script_ast::Node,
2563    ) -> SingleMutLocationExpression {
2564        SingleMutLocationExpression(SingleLocationExpression {
2565            kind,
2566            ty,
2567            starting_variable: Rc::new(Variable {
2568                name: Node::default(),
2569                resolved_type: Type::Int,
2570                mutable_node: None,
2571                scope_index: 0,
2572                variable_index: 0,
2573            }),
2574            node: self.to_node(ast_node),
2575            access_chain: vec![],
2576        })
2577    }
2578
2579    #[must_use]
2580    pub fn create_single_location_expr(
2581        &self,
2582        kind: SingleLocationExpressionKind,
2583        ty: Type,
2584        ast_node: &swamp_script_ast::Node,
2585    ) -> SingleLocationExpression {
2586        SingleLocationExpression {
2587            kind,
2588            ty,
2589            starting_variable: Rc::new(Variable {
2590                name: Node::default(),
2591                resolved_type: Type::Int,
2592                mutable_node: None,
2593                scope_index: 0,
2594                variable_index: 0,
2595            }),
2596            node: self.to_node(ast_node),
2597            access_chain: vec![],
2598        }
2599    }
2600
2601    #[must_use]
2602    pub fn create_single_location_expr_resolved(
2603        &self,
2604        kind: SingleLocationExpressionKind,
2605        ty: Type,
2606        node: &Node,
2607    ) -> SingleLocationExpression {
2608        SingleLocationExpression {
2609            kind,
2610            ty,
2611            starting_variable: Rc::new(Variable {
2612                name: Node::default(),
2613                resolved_type: Type::Int,
2614                mutable_node: None,
2615                scope_index: 0,
2616                variable_index: 0,
2617            }),
2618            node: node.clone(),
2619            access_chain: vec![],
2620        }
2621    }
2622    #[must_use]
2623    pub fn create_mut_single_location_expr_resolved(
2624        &self,
2625        kind: SingleLocationExpressionKind,
2626        ty: Type,
2627        node: &Node,
2628    ) -> SingleMutLocationExpression {
2629        SingleMutLocationExpression(SingleLocationExpression {
2630            kind,
2631            ty,
2632            starting_variable: Rc::new(Variable {
2633                name: Node::default(),
2634                resolved_type: Type::Int,
2635                mutable_node: None,
2636                scope_index: 0,
2637                variable_index: 0,
2638            }),
2639            node: node.clone(),
2640            access_chain: vec![],
2641        })
2642    }
2643
2644    #[must_use]
2645    pub const fn create_expr(
2646        &self,
2647        kind: ExpressionKind,
2648        ty: Type,
2649        ast_node: &swamp_script_ast::Node,
2650    ) -> Expression {
2651        //info!(%ty, ?kind, "create_expr()");
2652        Expression {
2653            kind,
2654            ty,
2655            node: self.to_node(ast_node),
2656        }
2657    }
2658
2659    #[must_use]
2660    pub fn create_expr_resolved(
2661        &self,
2662        kind: ExpressionKind,
2663        ty: Type,
2664        ast_node: &Node,
2665    ) -> Expression {
2666        Expression {
2667            kind,
2668            ty,
2669            node: ast_node.clone(),
2670        }
2671    }
2672
2673    fn analyze_destructuring(
2674        &mut self,
2675        node: &swamp_script_ast::Node,
2676        target_ast_variables: &[swamp_script_ast::Variable],
2677        tuple_expression: &swamp_script_ast::Expression,
2678    ) -> Result<Expression, Error> {
2679        let any_context = TypeContext::new_anything_argument();
2680        let tuple_resolved = self.analyze_expression(tuple_expression, &any_context)?;
2681        let tuple_expr_type = &tuple_resolved.ty;
2682
2683        let mut variable_refs = Vec::new();
2684        if let Type::Tuple(tuple) = tuple_expr_type.clone() {
2685            if target_ast_variables.len() > tuple.0.len() {
2686                return Err(self.create_err(ErrorKind::TooManyDestructureVariables, node));
2687            }
2688            for (variable_ref, tuple_type) in target_ast_variables.iter().zip(tuple.0.clone()) {
2689                let (variable_ref, _is_reassignment) =
2690                    self.set_or_overwrite_variable_with_type(variable_ref, &tuple_type)?;
2691                variable_refs.push(variable_ref);
2692            }
2693            let expr_kind =
2694                ExpressionKind::TupleDestructuring(variable_refs, tuple, Box::from(tuple_resolved));
2695
2696            Ok(self.create_expr(expr_kind, Type::Unit, node))
2697        } else {
2698            Err(self.create_err(ErrorKind::CanNotDestructure, node))
2699        }
2700    }
2701
2702    fn analyze_postfix_member_func_call(
2703        &mut self,
2704        resolved_node: &Node,
2705        found_function: &FunctionRef,
2706        struct_type: &StructTypeRef,
2707        is_mutable: bool,
2708        arguments: &[swamp_script_ast::MutableOrImmutableExpression],
2709    ) -> Result<Postfix, Error> {
2710        let signature = found_function.signature();
2711
2712        let self_type = &signature.parameters[0];
2713        if !self_type
2714            .resolved_type
2715            .compatible_with(&Type::Struct(struct_type.clone()))
2716            || self_type.is_mutable && !is_mutable
2717        {
2718            return Err(self.create_err_resolved(ErrorKind::SelfNotCorrectType, resolved_node));
2719        }
2720
2721        let resolved_arguments = self.analyze_and_verify_parameters(
2722            resolved_node,
2723            &signature.parameters[1..],
2724            arguments,
2725        )?;
2726
2727        let kind = PostfixKind::MemberCall(found_function.clone(), resolved_arguments);
2728        let postfix = Postfix {
2729            node: resolved_node.clone(),
2730            ty: *signature.return_type.clone(),
2731            kind,
2732        };
2733
2734        Ok(postfix)
2735    }
2736
2737    fn analyze_postfix_field_call(
2738        &mut self,
2739        resolved_node: &Node,
2740        struct_type: &StructTypeRef,
2741        field: &StructTypeField,
2742        index: usize,
2743        signature: &Signature,
2744        arguments: &[swamp_script_ast::MutableOrImmutableExpression],
2745    ) -> Result<Vec<Postfix>, Error> {
2746        let mut suffixes = Vec::new();
2747        //let field_name_str = self.get_text(member_name).to_string();
2748        let struct_field_kind = PostfixKind::StructField(struct_type.clone(), index);
2749
2750        let struct_field_postfix = Postfix {
2751            node: resolved_node.clone(),
2752            ty: field.field_type.clone(),
2753            kind: struct_field_kind,
2754        };
2755
2756        suffixes.push(struct_field_postfix);
2757
2758        let resolved_arguments =
2759            self.analyze_and_verify_parameters(resolved_node, &signature.parameters, arguments)?;
2760
2761        let call_kind = PostfixKind::FunctionCall(resolved_arguments);
2762
2763        let call_postfix = Postfix {
2764            node: resolved_node.clone(),
2765            ty: *signature.return_type.clone(),
2766            kind: call_kind,
2767        };
2768        suffixes.push(call_postfix);
2769
2770        Ok(suffixes)
2771    }
2772
2773    fn analyze_postfix_member_call(
2774        &mut self,
2775        struct_type: &StructTypeRef,
2776        is_mutable: bool,
2777        member_name: &swamp_script_ast::Node,
2778        arguments: &[swamp_script_ast::MutableOrImmutableExpression],
2779        suffixes: &mut Vec<Postfix>,
2780    ) -> Result<Type, Error> {
2781        let field_name_str = self.get_text(member_name).to_string();
2782
2783        let resolved_node = self.to_node(member_name);
2784        let binding = struct_type.borrow();
2785        let postfixes = match binding.functions.get(&field_name_str) {
2786            Some(found_function_member) => {
2787                let postfix = self.analyze_postfix_member_func_call(
2788                    &resolved_node,
2789                    found_function_member,
2790                    struct_type,
2791                    is_mutable,
2792                    arguments,
2793                )?;
2794                vec![postfix]
2795            }
2796            _ => match binding.anon_struct_type.defined_fields.get(&field_name_str) {
2797                Some(found_field) => {
2798                    if let Type::Function(signature) = &found_field.field_type {
2799                        let index = binding
2800                            .anon_struct_type
2801                            .defined_fields
2802                            .get_index(&field_name_str)
2803                            .expect("should work");
2804                        self.analyze_postfix_field_call(
2805                            &resolved_node,
2806                            struct_type,
2807                            found_field,
2808                            index,
2809                            signature,
2810                            arguments,
2811                        )?
2812                    } else {
2813                        return Err(
2814                            self.create_err(ErrorKind::NotValidLocationStartingPoint, member_name)
2815                        );
2816                    }
2817                }
2818                _ => {
2819                    return Err(
2820                        self.create_err(ErrorKind::NotValidLocationStartingPoint, member_name)
2821                    );
2822                }
2823            },
2824        };
2825
2826        let last_type = postfixes.last().unwrap().ty.clone();
2827        suffixes.extend(postfixes);
2828
2829        Ok(last_type)
2830    }
2831
2832    /*
2833    pub fn analyze_range(&mut self, min_value: &Expression, max_value: &Expression, range_mode: &RangeMode) -> Range {
2834        let min_expression =
2835            self.analyze_expression(min_value, Some(&Type::Int))?;
2836        let max_expression =
2837            self.analyze_expression(max_value, Some(&Type::Int))?;
2838
2839        Range {
2840            min: min_expression,
2841            max: max_expression,
2842            mode: convert_range_mode(range_mode),
2843        }
2844    }
2845
2846     */
2847    fn analyze_break(
2848        &self,
2849        context: &TypeContext,
2850        node: &swamp_script_ast::Node,
2851    ) -> Result<Expression, Error> {
2852        if !context.allows_break() {
2853            return Err(self.create_err(ErrorKind::BreakOutsideLoop, node));
2854        }
2855
2856        Ok(Expression {
2857            kind: ExpressionKind::Break,
2858            ty: Type::Never,
2859            node: self.to_node(node),
2860        })
2861    }
2862
2863    fn analyze_return(
2864        &mut self,
2865        context: &TypeContext,
2866        optional_expression: Option<&swamp_script_ast::Expression>,
2867        node: &swamp_script_ast::Node,
2868    ) -> Result<Expression, Error> {
2869        if !context.allows_return() {
2870            return Err(self.create_err(ErrorKind::ReturnOutsideCompare, node));
2871        }
2872
2873        let return_context = context.for_return();
2874        let inner = if let Some(expr) = optional_expression {
2875            Some(Box::new(self.analyze_expression(expr, &return_context)?))
2876        } else {
2877            // Empty return
2878            None
2879        };
2880
2881        Ok(self.create_expr(ExpressionKind::Return(inner), Type::Never, node))
2882    }
2883
2884    fn analyze_continue(
2885        &self,
2886        context: &TypeContext,
2887        node: &swamp_script_ast::Node,
2888    ) -> Result<Expression, Error> {
2889        if !context.allows_continue() {
2890            return Err(self.create_err(ErrorKind::ContinueOutsideLoop, node));
2891        }
2892        Ok(self.create_expr(ExpressionKind::Continue, Type::Never, node))
2893    }
2894}