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