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