Skip to main content

mysz_core/semantics/
analyser.rs

1use crate::parse::parsing::*;
2use crate::semantics::analysis::{FunctionSignature, Scope, StructSignature, Symbol};
3use crate::utils::location::Location;
4use crate::utils::typesafe::*;
5use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone)]
8pub enum AnalyserError {
9    TypeError { location: Location, message: String },
10    SemanticError { location: Location, message: String },
11}
12impl AnalyserError {
13    pub fn type_error(location: Location, message: impl Into<String>) -> Self {
14        AnalyserError::TypeError {
15            location,
16            message: message.into(),
17        }
18    }
19    pub fn semantic_error(location: Location, message: impl Into<String>) -> Self {
20        AnalyserError::SemanticError {
21            location,
22            message: message.into(),
23        }
24    }
25}
26
27fn contains_generic_param(ty: &Type) -> bool {
28    match ty {
29        Type::GenericParam(_) => true,
30        Type::Ptr(inner) => contains_generic_param(inner),
31        Type::Array { element_type, .. } => contains_generic_param(element_type),
32        Type::GenericInstance { args, .. } => args.iter().any(contains_generic_param),
33        _ => false,
34    }
35}
36
37#[derive(Debug)]
38pub struct Analyser {
39    pub scopes: Vec<Scope>,
40    pub current_scope: usize,
41    pub functions: HashMap<String, FunctionSignature>,
42    pub structs: HashMap<String, StructSignature>,
43    pub constants: HashMap<String, (Type, Expr)>,
44    current_return_type: Option<Type>,
45    loop_depth: usize,
46    pub current_generic_params: Vec<String>,
47}
48
49impl Analyser {
50    pub fn new() -> Self {
51        Self {
52            scopes: vec![Scope {
53                symbols: HashMap::new(),
54                parent: None,
55            }],
56            current_scope: 0,
57            functions: HashMap::new(),
58            structs: HashMap::new(),
59            constants: HashMap::new(),
60            current_return_type: None,
61            loop_depth: 0,
62            current_generic_params: Vec::new(),
63        }
64    }
65
66    pub fn enter_scope(&mut self) {
67        let parent_idx = self.current_scope;
68        let new_scope = Scope {
69            symbols: HashMap::new(),
70            parent: Some(parent_idx),
71        };
72        self.scopes.push(new_scope);
73        self.current_scope = self.scopes.len() - 1;
74    }
75
76    pub fn leave_scope(&mut self) {
77        let parent = self.scopes[self.current_scope]
78            .parent
79            .expect("Attempted to leave global scope");
80
81        self.scopes.pop();
82        self.current_scope = parent;
83    }
84
85    fn substitute_type(&self, ty: &Type, mapping: &HashMap<String, Type>) -> Type {
86        match ty {
87            Type::GenericParam(name) => mapping
88                .get(name)
89                .cloned()
90                .unwrap_or_else(|| Type::GenericParam(name.clone())),
91            Type::Struct(name) => mapping.get(name).cloned().unwrap_or_else(|| ty.clone()),
92            Type::Ptr(inner) => Type::Ptr(Box::new(self.substitute_type(inner, mapping))),
93            Type::Array { element_type, size } => Type::Array {
94                element_type: Box::new(self.substitute_type(element_type, mapping)),
95                size: *size,
96            },
97            Type::GenericInstance { name, args } => {
98                let substituted_args = args
99                    .iter()
100                    .map(|arg| self.substitute_type(arg, mapping))
101                    .collect();
102                Type::GenericInstance {
103                    name: name.clone(),
104                    args: substituted_args,
105                }
106            }
107            _ => ty.clone(),
108        }
109    }
110
111    fn instantiate_generic_types(
112        &mut self,
113        ty: &Type,
114        span: &Location,
115    ) -> Result<Type, AnalyserError> {
116        match ty {
117            Type::Ptr(inner) => {
118                let inst = self.instantiate_generic_types(inner, span)?;
119                Ok(Type::Ptr(Box::new(inst)))
120            }
121            Type::Array { element_type, size } => {
122                let inst = self.instantiate_generic_types(element_type, span)?;
123                Ok(Type::Array {
124                    element_type: Box::new(inst),
125                    size: *size,
126                })
127            }
128            Type::GenericInstance { name, args } => {
129                let mut resolved_args = Vec::new();
130                for arg in args {
131                    resolved_args.push(self.instantiate_generic_types(arg, span)?);
132                }
133
134                if resolved_args.iter().any(contains_generic_param) {
135                    return Ok(Type::GenericInstance {
136                        name: name.clone(),
137                        args: resolved_args,
138                    });
139                }
140
141                let template = self
142                    .structs
143                    .get(name)
144                    .ok_or_else(|| AnalyserError::SemanticError {
145                        location: span.clone(),
146                        message: format!("Semantic Error: Generic struct '{}' not found.", name),
147                    })?
148                    .clone();
149
150                if template.generic_params.len() != resolved_args.len() {
151                    return Err(AnalyserError::TypeError {
152                        location: span.clone(),
153                        message: format!(
154                            "Type Error: Struct '{}' expects {} type parameters, found {}",
155                            name,
156                            template.generic_params.len(),
157                            resolved_args.len()
158                        ),
159                    });
160                }
161
162                let mangled = mangle_name(name, &resolved_args);
163
164                if !self.structs.contains_key(&mangled) {
165                    let mapping: HashMap<String, Type> = template
166                        .generic_params
167                        .iter()
168                        .cloned()
169                        .zip(resolved_args.iter().cloned())
170                        .collect();
171
172                    let mut fresh_fields = HashMap::new();
173                    for (f_name, f_type) in &template.fields {
174                        let substituted = self.substitute_type(f_type, &mapping);
175                        fresh_fields.insert(f_name.clone(), substituted);
176                    }
177
178                    self.structs.insert(
179                        mangled.clone(),
180                        StructSignature {
181                            generic_params: Vec::new(),
182                            fields: fresh_fields,
183                            location: span.clone(),
184                        },
185                    );
186                }
187
188                Ok(Type::Struct(mangled))
189            }
190            Type::GenericParam(p) => Ok(Type::GenericParam(p.clone())),
191            _ => Ok(ty.clone()),
192        }
193    }
194
195    fn declare_variable(
196        &mut self,
197        name: &str,
198        data_type: Type,
199        span: Location,
200    ) -> Result<(), AnalyserError> {
201        let scope = &mut self.scopes[self.current_scope];
202        if scope.symbols.contains_key(name) {
203            return Err(AnalyserError::SemanticError {
204                location: span,
205                message: format!(
206                    "Semantic Error: Variable '{}' already declared in this scope.",
207                    name
208                ),
209            });
210        }
211        scope.symbols.insert(
212            name.to_string(),
213            Symbol {
214                name: name.to_string(),
215                ty: data_type,
216            },
217        );
218        Ok(())
219    }
220
221    fn resolve_variable(&self, name: &str) -> Option<&Symbol> {
222        let mut current = self.current_scope;
223        loop {
224            if let Some(symbol) = self.scopes[current].symbols.get(name) {
225                return Some(symbol);
226            }
227            match self.scopes[current].parent {
228                Some(p) => current = p,
229                None => break,
230            }
231        }
232        None
233    }
234
235    fn validate_type_exists(&self, ty: &Type, span: &Location) -> Result<(), AnalyserError> {
236        match ty {
237            Type::Struct(name) => {
238                if self.current_generic_params.contains(name) {
239                    return Ok(());
240                }
241
242                if !self.structs.contains_key(name) {
243                    return Err(AnalyserError::SemanticError {
244                        location: span.clone(),
245                        message: format!(
246                            "Semantic Error: Type '{}' is used here but never defined.",
247                            name
248                        ),
249                    });
250                }
251            }
252            Type::GenericInstance { name, args } => {
253                if !self.structs.contains_key(name) {
254                    return Err(AnalyserError::SemanticError {
255                        location: span.clone(),
256                        message: format!(
257                            "Semantic Error: Generic Struct '{}' is used here but never defined.",
258                            name
259                        ),
260                    });
261                }
262                for arg in args {
263                    self.validate_type_exists(arg, span)?;
264                }
265            }
266            Type::Ptr(inner) => {
267                self.validate_type_exists(inner, span)?;
268            }
269            Type::Array { element_type, .. } => {
270                self.validate_type_exists(element_type, span)?;
271            }
272            _ => {}
273        }
274        Ok(())
275    }
276
277    fn declare_struct(
278        &mut self,
279        name: &str,
280        generic_params: Vec<String>,
281        fields: HashMap<String, Type>,
282        location: Location,
283    ) -> Result<(), AnalyserError> {
284        if let Some(existing) = self.structs.get(name) {
285            return Err(AnalyserError::SemanticError {
286                location,
287                message: format!(
288                    "Semantic Error: Struct '{}' is already defined at [{}]",
289                    name, existing.location
290                ),
291            });
292        }
293
294        self.structs.insert(
295            name.to_string(),
296            StructSignature {
297                generic_params,
298                fields,
299                location,
300            },
301        );
302
303        Ok(())
304    }
305
306    fn declare_function(
307        &mut self,
308        name: &str,
309        generic_params: Vec<String>,
310        param_types: Vec<Type>,
311        return_type: Type,
312        location: Location,
313    ) -> Result<(), AnalyserError> {
314        if let Some(existing) = self.functions.get(name) {
315            return Err(AnalyserError::SemanticError {
316                location,
317                message: format!(
318                    "Semantic Error: Function '{}' is already defined at [{}]",
319                    name, existing.location
320                ),
321            });
322        }
323
324        self.functions.insert(
325            name.to_string(),
326            FunctionSignature {
327                generic_params,
328                param_types,
329                return_type,
330                location,
331            },
332        );
333
334        Ok(())
335    }
336
337    fn resolve_function(&self, name: &str) -> Option<&FunctionSignature> {
338        self.functions.get(name)
339    }
340
341    pub fn check_truthiness(&self, ty: &Type) -> bool {
342        is_truthy_type(ty)
343    }
344
345    pub fn check_expr(
346        &mut self,
347        expr: &Expr,
348        expected_type: Option<&Type>,
349    ) -> Result<Type, AnalyserError> {
350        match &expr.kind {
351            ExprKind::Sizeof { .. } => Ok(Type::Int),
352            ExprKind::Cast { left, right } => {
353                let leftty = self.check_expr(left.as_ref(), None)?;
354                if types_compatible(&leftty, right) {
355                    return Ok(right.clone());
356                }
357                Err(AnalyserError::type_error(
358                    expr.span.clone(),
359                    format!(
360                        "Cannot cast '{}' to '{}'",
361                        type_to_string(&leftty),
362                        type_to_string(right)
363                    ),
364                ))
365            }
366            ExprKind::Literal(lit) => match lit {
367                Literal::Int(_) => {
368                    if let Some(Type::UInt) = expected_type {
369                        Ok(Type::UInt)
370                    } else {
371                        Ok(Type::Int)
372                    }
373                }
374                Literal::String(_) => Ok(Type::Str),
375                Literal::Bool(_) => Ok(Type::Bool),
376                Literal::Char(_) => Ok(Type::Char),
377                Literal::Arr { elements } => {
378                    let expected_elem_ty = match expected_type {
379                        Some(Type::Array { element_type, .. }) => Some(&**element_type),
380                        _ => None,
381                    };
382
383                    let element_type = if elements.is_empty() {
384                        if let Some(elem_ty) = expected_elem_ty {
385                            elem_ty.clone()
386                        } else {
387                            return Err(AnalyserError::type_error(
388                            expr.span.clone(),
389                            "Cannot infer the type of an empty array literal without explicit type context."
390                                .to_string(),
391                        ));
392                        }
393                    } else {
394                        self.check_expr(&elements[0], expected_elem_ty)?
395                    };
396
397                    for el in elements {
398                        let el_type = self.check_expr(el, Some(&element_type))?;
399                        if !types_equal(&element_type, &el_type) {
400                            return Err(AnalyserError::type_error(
401                                el.span.clone(),
402                                format!(
403                                    "Heterogeneous array literals are not allowed. Expected elements of type '{}', found '{}'.",
404                                    type_to_string(&element_type),
405                                    type_to_string(&el_type)
406                                ),
407                            ));
408                        }
409                    }
410
411                    Ok(Type::Array {
412                        element_type: Box::new(element_type),
413                        size: elements.len(),
414                    })
415                }
416            },
417            ExprKind::Field { base, field } => {
418                let base_type = self.check_expr(base, None)?;
419
420                match base_type {
421                    Type::Struct(struct_name) => {
422                        let signature = self.structs.get(&struct_name).ok_or_else(|| {
423                            AnalyserError::semantic_error(
424                                expr.span.clone(),
425                                format!(
426                                    "Attempted to access field '{}' on undefined struct '{}'.",
427                                    field, struct_name
428                                ),
429                            )
430                        })?;
431
432                        let field_type = signature.fields.get(field).ok_or_else(|| {
433                            AnalyserError::semantic_error(
434                                expr.span.clone(),
435                                format!("Struct '{}' has no field named '{}'.", struct_name, field),
436                            )
437                        })?;
438
439                        Ok(field_type.clone())
440                    }
441                    Type::GenericInstance { name, args } => {
442                        let signature = self.structs.get(&name).ok_or_else(|| {
443                            AnalyserError::semantic_error(
444                                expr.span.clone(),
445                                format!(
446                                    "Attempted to access field '{}' on undefined struct '{}'.",
447                                    field, name
448                                ),
449                            )
450                        })?;
451
452                        let raw_field_type = signature.fields.get(field).ok_or_else(|| {
453                            AnalyserError::semantic_error(
454                                expr.span.clone(),
455                                format!("Struct '{}' has no field named '{}'.", name, field),
456                            )
457                        })?;
458
459                        let mapping: HashMap<String, Type> = signature
460                            .generic_params
461                            .iter()
462                            .cloned()
463                            .zip(args.iter().cloned())
464                            .collect();
465
466                        Ok(self.substitute_type(raw_field_type, &mapping))
467                    }
468                    _ => Err(AnalyserError::type_error(
469                        expr.span.clone(),
470                        format!(
471                            "Cannot access a field on non-struct type '{}'.",
472                            type_to_string(&base_type)
473                        ),
474                    )),
475                }
476            }
477            ExprKind::StructLiteral {
478                struct_name,
479                generic_args,
480                fields,
481            } => {
482                let concrete_ty = if generic_args.is_empty() {
483                    let template = self.structs.get(struct_name).ok_or_else(|| {
484                        AnalyserError::semantic_error(
485                            expr.span.clone(),
486                            format!("Undefined struct '{}'.", struct_name),
487                        )
488                    })?;
489                    if !template.generic_params.is_empty() {
490                        return Err(AnalyserError::type_error(
491                            expr.span.clone(),
492                            format!("Struct '{}' requires generic arguments.", struct_name),
493                        ));
494                    }
495                    Type::Struct(struct_name.clone())
496                } else {
497                    let generic_ty = Type::GenericInstance {
498                        name: struct_name.clone(),
499                        args: generic_args.clone(),
500                    };
501                    self.validate_type_exists(&generic_ty, &expr.span)?;
502                    self.instantiate_generic_types(&generic_ty, &expr.span)?
503                };
504
505                let concrete_name = match &concrete_ty {
506                    Type::Struct(name) => name.clone(),
507                    _ => {
508                        return Err(AnalyserError::type_error(
509                            expr.span.clone(),
510                            format!("Expected concrete struct type, got {:?}", concrete_ty),
511                        ));
512                    }
513                };
514                let struct_def = self
515                    .structs
516                    .get(&concrete_name)
517                    .ok_or_else(|| {
518                        AnalyserError::semantic_error(
519                            expr.span.clone(),
520                            format!("Instantiated struct '{}' not found.", concrete_name),
521                        )
522                    })?
523                    .clone();
524
525                if fields.len() != struct_def.fields.len() {
526                    return Err(AnalyserError::type_error(
527                        expr.span.clone(),
528                        format!(
529                            "Struct '{}' expects {} fields, found {}.",
530                            concrete_name,
531                            struct_def.fields.len(),
532                            fields.len()
533                        ),
534                    ));
535                }
536
537                let mut seen_fields = HashSet::new();
538                for (field_name, field_expr) in fields {
539                    if !seen_fields.insert(field_name) {
540                        return Err(AnalyserError::semantic_error(
541                            field_expr.span.clone(),
542                            format!("Duplicate field '{}' in struct literal.", field_name),
543                        ));
544                    }
545
546                    let expected_ty = struct_def.fields.get(field_name).ok_or_else(|| {
547                        AnalyserError::semantic_error(
548                            field_expr.span.clone(),
549                            format!(
550                                "Field '{}' does not exist in struct '{}'.",
551                                field_name, concrete_name
552                            ),
553                        )
554                    })?;
555
556                    let actual_ty = self.check_expr(field_expr, Some(expected_ty))?;
557                    if !types_equal(expected_ty, &actual_ty) {
558                        return Err(AnalyserError::type_error(
559                            field_expr.span.clone(),
560                            format!(
561                                "Field '{}' expects type '{}', but found '{}'.",
562                                field_name,
563                                type_to_string(expected_ty),
564                                type_to_string(&actual_ty)
565                            ),
566                        ));
567                    }
568                }
569
570                Ok(concrete_ty)
571            }
572            ExprKind::Index { base, index } => {
573                let base_type = self.check_expr(base, None)?;
574                let index_type = self.check_expr(index, Some(&Type::Int))?;
575
576                if !is_integer(&index_type) {
577                    return Err(AnalyserError::type_error(
578                        index.span.clone(),
579                        format!(
580                            "Array index must be an integer, found '{}'.",
581                            type_to_string(&index_type)
582                        ),
583                    ));
584                }
585
586                match base_type {
587                    Type::Array { element_type, .. } => Ok(*element_type),
588                    Type::Ptr(inner_type) => Ok(*inner_type),
589                    _ => Err(AnalyserError::type_error(
590                        expr.span.clone(),
591                        format!(
592                            "Cannot index into non-indexable type '{}'.",
593                            type_to_string(&base_type)
594                        ),
595                    )),
596                }
597            }
598            ExprKind::Identifier(name) => {
599                if let Some(symbol) = self.resolve_variable(name) {
600                    Ok(symbol.ty.clone())
601                } else if let Some((const_type, _)) = self.constants.get(name) {
602                    Ok(const_type.clone())
603                } else {
604                    Err(AnalyserError::semantic_error(
605                        expr.span.clone(),
606                        format!("Symbol '{}' is used before definition.", name),
607                    ))
608                }
609            }
610            ExprKind::Call {
611                callee,
612                generic_args,
613                args,
614            } => {
615                let template = self
616                    .resolve_function(&callee.value)
617                    .ok_or_else(|| {
618                        AnalyserError::semantic_error(
619                            callee.location.clone(),
620                            format!("Call to undefined function '{}'", callee.value),
621                        )
622                    })?
623                    .clone();
624
625                let mut resolved_func_name = callee.value.clone();
626
627                if !template.generic_params.is_empty() || !generic_args.is_empty() {
628                    if template.generic_params.len() != generic_args.len() {
629                        return Err(AnalyserError::type_error(
630                            expr.span.clone(),
631                            format!(
632                                "Function '{}' expects {} type parameters, found {}",
633                                callee.value,
634                                template.generic_params.len(),
635                                generic_args.len()
636                            ),
637                        ));
638                    }
639
640                    let mut inst_args = Vec::new();
641                    for g_arg in generic_args {
642                        inst_args.push(self.instantiate_generic_types(g_arg, &callee.location)?);
643                    }
644
645                    resolved_func_name = mangle_name(&callee.value, &inst_args);
646
647                    if !self.functions.contains_key(&resolved_func_name) {
648                        let mut mapping: HashMap<String, Type> = HashMap::new();
649                        for (param_name, concrete_type) in
650                            template.generic_params.iter().zip(&inst_args)
651                        {
652                            mapping.insert(param_name.clone(), concrete_type.clone());
653                            mapping
654                                .insert(format!("gparam__{}", param_name), concrete_type.clone());
655                        }
656
657                        let substituted_return =
658                            self.substitute_type(&template.return_type, &mapping);
659                        let fresh_return =
660                            self.instantiate_generic_types(&substituted_return, &callee.location)?;
661
662                        let mut fresh_params = Vec::new();
663                        for p_ty in &template.param_types {
664                            let substituted_param = self.substitute_type(p_ty, &mapping);
665                            let fully_resolved_param = self
666                                .instantiate_generic_types(&substituted_param, &callee.location)?;
667                            fresh_params.push(fully_resolved_param);
668                        }
669
670                        self.functions.insert(
671                            resolved_func_name.clone(),
672                            FunctionSignature {
673                                generic_params: Vec::new(),
674                                param_types: fresh_params,
675                                return_type: fresh_return,
676                                location: template.location.clone(),
677                            },
678                        );
679                    }
680                }
681
682                let sig = self.functions.get(&resolved_func_name).unwrap();
683
684                if args.len() != sig.param_types.len() {
685                    return Err(AnalyserError::type_error(
686                        expr.span.clone(),
687                        format!(
688                            "Function '{}' expects {} argument(s), found {}",
689                            callee.value,
690                            sig.param_types.len(),
691                            args.len()
692                        ),
693                    ));
694                }
695
696                let param_types = sig.param_types.clone();
697                let return_type = sig.return_type.clone();
698
699                for (i, (arg, expected)) in args.iter().zip(param_types.iter()).enumerate() {
700                    let arg_type = self.check_expr(arg, Some(expected))?;
701                    match (expected, &arg_type) {
702                        (
703                            Type::Array {
704                                element_type: expected_elem,
705                                ..
706                            },
707                            Type::Array {
708                                element_type: actual_elem,
709                                ..
710                            },
711                        ) => {
712                            if **expected_elem != Type::Any
713                                && !types_equal(expected_elem, actual_elem)
714                            {
715                                return Err(AnalyserError::type_error(
716                                    arg.span.clone(),
717                                    format!(
718                                        "Argument {} to '{}' expects array of '{}', found array of '{}'",
719                                        i + 1,
720                                        callee.value,
721                                        type_to_string(expected_elem),
722                                        type_to_string(actual_elem),
723                                    ),
724                                ));
725                            }
726                        }
727
728                        (Type::Array { .. }, _) => {
729                            return Err(AnalyserError::type_error(
730                                arg.span.clone(),
731                                format!(
732                                    "Argument {} to '{}' expects '{}', found '{}'",
733                                    i + 1,
734                                    callee.value,
735                                    type_to_string(expected),
736                                    type_to_string(&arg_type),
737                                ),
738                            ));
739                        }
740
741                        _ => {
742                            if !types_equal(expected, &arg_type) {
743                                return Err(AnalyserError::type_error(
744                                    arg.span.clone(),
745                                    format!(
746                                        "Argument {} to '{}' expects '{}', found '{}'",
747                                        i + 1,
748                                        callee.value,
749                                        type_to_string(expected),
750                                        type_to_string(&arg_type),
751                                    ),
752                                ));
753                            }
754                        }
755                    }
756                }
757
758                Ok(return_type)
759            }
760
761            ExprKind::Binary { left, op, right } => {
762                let left_type = self.check_expr(left, None)?;
763                let right_type = self.check_expr(right, Some(&left_type))?;
764
765                match op {
766                    BinaryOp::Add => {
767                        if is_integer(&left_type) && is_integer(&right_type) {
768                            if left_type == right_type {
769                                Ok(left_type)
770                            } else {
771                                Err(AnalyserError::type_error(
772                                    expr.span.clone(),
773                                    format!(
774                                        "Cannot add mismatched integer types '{}' and '{}'",
775                                        type_to_string(&left_type),
776                                        type_to_string(&right_type)
777                                    ),
778                                ))
779                            }
780                        } else if Type::Str != left_type && Type::Str != right_type {
781                            Ok(Type::Str)
782                        } else {
783                            Err(AnalyserError::type_error(
784                                expr.span.clone(),
785                                format!(
786                                    "Cannot add type '{}' and '{}'",
787                                    type_to_string(&left_type),
788                                    type_to_string(&right_type)
789                                ),
790                            ))
791                        }
792                    }
793                    BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => {
794                        if is_integer(&left_type) && is_integer(&right_type) {
795                            if types_equal(&left_type, &right_type) {
796                                Ok(left_type)
797                            } else {
798                                Err(AnalyserError::type_error(
799                                    expr.span.clone(),
800                                    format!(
801                                        "Mixed-type integer arithmetic ('{}' and '{}') is not allowed",
802                                        type_to_string(&left_type),
803                                        type_to_string(&right_type)
804                                    ),
805                                ))
806                            }
807                        } else {
808                            Err(AnalyserError::type_error(
809                                expr.span.clone(),
810                                format!(
811                                    "Operator '{:?}' expects integers, but found '{}' and '{}'",
812                                    op,
813                                    type_to_string(&left_type),
814                                    type_to_string(&right_type)
815                                ),
816                            ))
817                        }
818                    }
819                    BinaryOp::Eq
820                    | BinaryOp::NEq
821                    | BinaryOp::Gt
822                    | BinaryOp::GtE
823                    | BinaryOp::And
824                    | BinaryOp::Or
825                    | BinaryOp::Lt
826                    | BinaryOp::LtE => {
827                        if types_equal(&left_type, &right_type) {
828                            Ok(Type::Bool)
829                        } else {
830                            Err(AnalyserError::type_error(
831                                expr.span.clone(),
832                                format!(
833                                    "Cannot compare incompatible types '{}' and '{}'",
834                                    type_to_string(&left_type),
835                                    type_to_string(&right_type)
836                                ),
837                            ))
838                        }
839                    }
840                }
841            }
842            ExprKind::Unary { op, expr: sub_expr } => {
843                let expr_type = self.check_expr(sub_expr, None)?;
844                match op {
845                    UnaryOp::Positive | UnaryOp::Negative => {
846                        if is_signed_integer(&expr_type) {
847                            Ok(expr_type)
848                        } else {
849                            Err(AnalyserError::type_error(
850                                expr.span.clone(),
851                                format!(
852                                    "Unary sign operators are only supported on signed integers, found '{}'",
853                                    type_to_string(&expr_type)
854                                ),
855                            ))
856                        }
857                    }
858                    UnaryOp::Not => {
859                        if expr_type == Type::Bool {
860                            Ok(Type::Bool)
861                        } else {
862                            Err(AnalyserError::type_error(
863                                expr.span.clone(),
864                                format!(
865                                    "Unary boolean operator expects 'bool', found '{}'",
866                                    type_to_string(&expr_type)
867                                ),
868                            ))
869                        }
870                    }
871                    UnaryOp::AddressOf => Ok(Type::Ptr(Box::new(expr_type))),
872                    UnaryOp::Deref => match expr_type {
873                        Type::Ptr(inner_type) => Ok(*inner_type),
874                        _ => Err(AnalyserError::type_error(
875                            expr.span.clone(),
876                            format!(
877                                "Cannot dereference non-pointer type '{}'",
878                                type_to_string(&expr_type)
879                            ),
880                        )),
881                    },
882                }
883            }
884        }
885    }
886
887    pub fn check_stmt(&mut self, stmt: &Stmt) -> Result<(), AnalyserError> {
888        match stmt {
889            Stmt::Use { .. } => unreachable!(),
890
891            Stmt::Struct {
892                name,
893                generic_params,
894                fields,
895            } => {
896                let mut struct_fields = HashMap::new();
897
898                let prev_generic_params =
899                    std::mem::replace(&mut self.current_generic_params, generic_params.clone());
900
901                for field in fields {
902                    let field_type = match &field.ptype {
903                        Some(t) => t.clone(),
904                        None => Type::Any,
905                    };
906
907                    if struct_fields.contains_key(&field.name.value) {
908                        return Err(AnalyserError::SemanticError {
909                            location: field.name.location.clone(),
910                            message: format!(
911                                "Semantic Error: Struct '{}' contains duplicate field '{}'",
912                                name.value, field.name.value
913                            ),
914                        });
915                    }
916
917                    struct_fields.insert(field.name.value.clone(), field_type);
918                }
919
920                self.declare_struct(
921                    &name.value,
922                    generic_params.clone(),
923                    struct_fields,
924                    name.location.clone(),
925                )?;
926
927                self.current_generic_params = prev_generic_params;
928
929                Ok(())
930            }
931
932            Stmt::Break { location } => {
933                if self.loop_depth == 0 {
934                    return Err(AnalyserError::SemanticError {
935                        location: location.clone(),
936                        message:
937                            "Semantic Error: Break statement must be in a while loop statement"
938                                .to_string(),
939                    });
940                }
941                Ok(())
942            }
943
944            Stmt::Extern {
945                name,
946                rttype,
947                generic_params,
948                params,
949            } => {
950                let return_type = match rttype {
951                    Some(rt) => {
952                        let instantiated = self.instantiate_generic_types(rt, &name.location)?;
953                        self.validate_type_exists(&instantiated, &name.location)?;
954                        instantiated
955                    }
956                    None => Type::Void,
957                };
958
959                let prev_generic_params =
960                    std::mem::replace(&mut self.current_generic_params, generic_params.clone());
961
962                let mut param_types = Vec::new();
963                for param in params {
964                    let ptype = match &param.ptype {
965                        Some(pt) => {
966                            let instantiated =
967                                self.instantiate_generic_types(pt, &param.name.location)?;
968                            self.validate_type_exists(&instantiated, &param.name.location)?;
969                            instantiated
970                        }
971                        None => Type::Any,
972                    };
973                    param_types.push(ptype);
974                }
975
976                self.current_generic_params = prev_generic_params;
977
978                self.declare_function(
979                    &name.value,
980                    generic_params.clone(),
981                    param_types,
982                    return_type,
983                    name.location.clone(),
984                )?;
985                Ok(())
986            }
987
988            Stmt::Constant { name, vtype, expr } => {
989                if self.current_return_type.is_some() {
990                    return Err(AnalyserError::SemanticError {
991                        location: name.location.clone(),
992                        message: format!(
993                            "Semantic Error: Constant '{}' cannot be defined inside a function.",
994                            name.value
995                        ),
996                    });
997                }
998
999                let const_type = match (vtype, expr) {
1000                    (Some(explicit_type), expr_node) => {
1001                        let instantiated =
1002                            self.instantiate_generic_types(explicit_type, &name.location)?;
1003                        self.validate_type_exists(&instantiated, &name.location)?;
1004                        let expr_type = self.check_expr(expr_node, Some(&instantiated))?;
1005                        if !types_equal(&instantiated, &expr_type) {
1006                            return Err(AnalyserError::TypeError {
1007                                location: expr_node.span.clone(),
1008                                message: format!(
1009                                    "Type Error: Constant '{}' declared as '{}' but initialiser has type '{}'",
1010                                    name.value,
1011                                    type_to_string(&instantiated),
1012                                    type_to_string(&expr_type)
1013                                ),
1014                            });
1015                        }
1016                        instantiated
1017                    }
1018                    (None, expr_node) => self.check_expr(expr_node, None)?,
1019                };
1020
1021                if self.constants.contains_key(&name.value) {
1022                    return Err(AnalyserError::SemanticError {
1023                        location: name.location.clone(),
1024                        message: format!(
1025                            "Semantic Error: Constant '{}' already defined.",
1026                            name.value
1027                        ),
1028                    });
1029                }
1030
1031                self.constants
1032                    .insert(name.value.clone(), (const_type, expr.clone()));
1033
1034                Ok(())
1035            }
1036
1037            Stmt::Assignment { ident, vtype, expr } => {
1038                let variable_type = match (vtype, expr) {
1039                    (Some(explicit_type), Some(expr_node)) => {
1040                        let instantiated =
1041                            self.instantiate_generic_types(explicit_type, &ident.location)?;
1042                        self.validate_type_exists(&instantiated, &ident.location)?;
1043                        let expr_type = self.check_expr(expr_node, Some(&instantiated))?;
1044
1045                        if !types_equal(&instantiated, &expr_type) {
1046                            return Err(AnalyserError::type_error(
1047                                expr_node.span.clone(),
1048                                format!(
1049                                    "Variable '{}' declared as '{}' but assigned type '{}'",
1050                                    ident.value,
1051                                    type_to_string(&instantiated),
1052                                    type_to_string(&expr_type)
1053                                ),
1054                            ));
1055                        }
1056                        instantiated
1057                    }
1058                    (Some(explicit_type), None) => {
1059                        let instantiated =
1060                            self.instantiate_generic_types(explicit_type, &ident.location)?;
1061                        self.validate_type_exists(&instantiated, &ident.location)?;
1062                        instantiated
1063                    }
1064                    (None, Some(expr_node)) => self.check_expr(expr_node, None)?,
1065                    (None, None) => {
1066                        return Err(AnalyserError::semantic_error(
1067                            ident.location.clone(),
1068                            format!(
1069                                "Variable '{}' declared without an explicit type or initializer expression.",
1070                                ident.value
1071                            ),
1072                        ));
1073                    }
1074                };
1075
1076                if let Some(existing_symbol) = self.resolve_variable(&ident.value) {
1077                    if !types_equal(&existing_symbol.ty, &variable_type) {
1078                        return Err(AnalyserError::type_error(
1079                            ident.location.clone(),
1080                            format!(
1081                                "Cannot reassign type '{}' to variable '{}' of type '{}'",
1082                                type_to_string(&variable_type),
1083                                ident.value,
1084                                type_to_string(&existing_symbol.ty)
1085                            ),
1086                        ));
1087                    }
1088                } else {
1089                    self.declare_variable(&ident.value, variable_type, ident.location.clone())?;
1090                }
1091
1092                Ok(())
1093            }
1094
1095            Stmt::DerefReassignment { target, expr } => {
1096                let target_resolved_type = self.check_expr(target, None)?;
1097                let expr_type = self.check_expr(expr, Some(&target_resolved_type))?;
1098
1099                if !types_equal(&target_resolved_type, &expr_type) {
1100                    return Err(AnalyserError::type_error(
1101                        expr.span.clone(),
1102                        format!(
1103                            "Cannot assign type '{}' to target location of type '{}'",
1104                            type_to_string(&expr_type),
1105                            type_to_string(&target_resolved_type)
1106                        ),
1107                    ));
1108                }
1109
1110                Ok(())
1111            }
1112
1113            Stmt::Reassignment { ident, expr } => {
1114                let expected_ty = self
1115                    .resolve_variable(&ident.value)
1116                    .map(|symbol| symbol.ty.clone())
1117                    .ok_or_else(|| {
1118                        AnalyserError::semantic_error(
1119                            ident.location.clone(),
1120                            format!("Cannot reassign to undefined variable '{}'", ident.value),
1121                        )
1122                    })?;
1123
1124                let expr_type = self.check_expr(expr, Some(&expected_ty))?;
1125
1126                if !types_equal(&expected_ty, &expr_type) {
1127                    return Err(AnalyserError::type_error(
1128                        expr.span.clone(),
1129                        format!(
1130                            "Cannot assign type '{}' to variable '{}' of type '{}'",
1131                            type_to_string(&expr_type),
1132                            ident.value,
1133                            type_to_string(&expected_ty)
1134                        ),
1135                    ));
1136                }
1137
1138                Ok(())
1139            }
1140
1141            Stmt::Expr(expr) => {
1142                self.check_expr(expr, None)?;
1143                Ok(())
1144            }
1145
1146            Stmt::While { cond, body } => {
1147                let cond_type = self.check_expr(cond, None)?;
1148                if !self.check_truthiness(&cond_type) {
1149                    return Err(AnalyserError::type_error(
1150                        cond.span.clone(),
1151                        format!(
1152                            "'while' condition is not truthy, found '{}'",
1153                            type_to_string(&cond_type)
1154                        ),
1155                    ));
1156                }
1157                self.enter_scope();
1158                self.loop_depth += 1;
1159                for block_stmt in body {
1160                    self.check_stmt(block_stmt)?;
1161                }
1162                self.leave_scope();
1163                self.loop_depth -= 1;
1164                Ok(())
1165            }
1166
1167            Stmt::For {
1168                init,
1169                cond,
1170                step,
1171                body,
1172            } => {
1173                self.enter_scope();
1174
1175                self.check_stmt(init.as_ref())?;
1176
1177                let cond_type = self.check_expr(cond, None)?;
1178                if !self.check_truthiness(&cond_type) {
1179                    self.leave_scope();
1180                    return Err(AnalyserError::type_error(
1181                        cond.span.clone(),
1182                        format!(
1183                            "'for' condition is not truthy, found '{}'",
1184                            type_to_string(&cond_type)
1185                        ),
1186                    ));
1187                }
1188
1189                for block_stmt in body {
1190                    self.check_stmt(block_stmt)?;
1191                }
1192
1193                self.check_stmt(step.as_ref())?;
1194
1195                self.leave_scope();
1196
1197                Ok(())
1198            }
1199
1200            Stmt::If {
1201                cond,
1202                then_branch,
1203                else_if_branches,
1204                else_branch,
1205            } => {
1206                let cond_type = self.check_expr(cond, None)?;
1207                if !self.check_truthiness(&cond_type) {
1208                    return Err(AnalyserError::type_error(
1209                        cond.span.clone(),
1210                        format!(
1211                            "'if' condition is not truthy, found '{}'",
1212                            type_to_string(&cond_type)
1213                        ),
1214                    ));
1215                }
1216
1217                self.enter_scope();
1218                for block_stmt in then_branch {
1219                    self.check_stmt(block_stmt)?;
1220                }
1221                self.leave_scope();
1222
1223                for (cond, body) in else_if_branches {
1224                    let cond_type = self.check_expr(cond, None)?;
1225                    if !self.check_truthiness(&cond_type) {
1226                        return Err(AnalyserError::type_error(
1227                            cond.span.clone(),
1228                            format!(
1229                                "'elseif' condition is not truthy, found '{}'",
1230                                type_to_string(&cond_type)
1231                            ),
1232                        ));
1233                    }
1234
1235                    self.enter_scope();
1236                    for body_stmt in body {
1237                        self.check_stmt(body_stmt)?;
1238                    }
1239                    self.leave_scope();
1240                }
1241
1242                if let Some(else_stmts) = else_branch {
1243                    self.enter_scope();
1244                    for block_stmt in else_stmts {
1245                        self.check_stmt(block_stmt)?;
1246                    }
1247                    self.leave_scope();
1248                }
1249
1250                Ok(())
1251            }
1252            Stmt::Function {
1253                name,
1254                public: _,
1255                rttype,
1256                generic_params,
1257                params,
1258                body,
1259            } => {
1260                let is_generic = !generic_params.is_empty();
1261
1262                let return_type = match rttype {
1263                    Some(rt) => {
1264                        if is_generic {
1265                            rt.clone()
1266                        } else {
1267                            let instantiated =
1268                                self.instantiate_generic_types(rt, &name.location)?;
1269                            self.validate_type_exists(&instantiated, &name.location)?;
1270                            instantiated
1271                        }
1272                    }
1273                    None => Type::Void,
1274                };
1275
1276                let prev_generic_params =
1277                    std::mem::replace(&mut self.current_generic_params, generic_params.clone());
1278
1279                let mut param_types = Vec::new();
1280                for param in params {
1281                    let ptype = match &param.ptype {
1282                        Some(pt) => {
1283                            if is_generic {
1284                                pt.clone()
1285                            } else {
1286                                let instantiated =
1287                                    self.instantiate_generic_types(pt, &param.name.location)?;
1288                                self.validate_type_exists(&instantiated, &param.name.location)?;
1289                                instantiated
1290                            }
1291                        }
1292                        None => Type::Any,
1293                    };
1294                    param_types.push(ptype);
1295                }
1296
1297                self.declare_function(
1298                    &name.value,
1299                    generic_params.clone(),
1300                    param_types.clone(),
1301                    return_type.clone(),
1302                    name.location.clone(),
1303                )?;
1304
1305                self.enter_scope();
1306                for (param, ptype) in params.iter().zip(param_types) {
1307                    self.declare_variable(&param.name.value, ptype, param.name.location.clone())?;
1308                }
1309
1310                let prev_return_type = self.current_return_type.replace(return_type.clone());
1311                let mut returns = false;
1312                for block_stmt in body {
1313                    if let Stmt::Return { .. } = block_stmt {
1314                        returns = true;
1315                    }
1316                    self.check_stmt(block_stmt)?;
1317                }
1318                self.current_return_type = prev_return_type;
1319
1320                if return_type != Type::Void && !returns {
1321                    return Err(AnalyserError::TypeError {
1322                        location: name.location.clone(),
1323                        message: format!(
1324                            "Type Error: Function '{}' must return a value of type '{}'",
1325                            name.value,
1326                            type_to_string(&return_type)
1327                        ),
1328                    });
1329                }
1330
1331                self.current_generic_params = prev_generic_params;
1332                self.leave_scope();
1333                Ok(())
1334            }
1335
1336            Stmt::Return { value, span } => {
1337                let expected = self.current_return_type.clone().ok_or_else(|| {
1338                    AnalyserError::SemanticError {
1339                        location: span.clone(),
1340                        message: "Semantic Error: 'return' used outside of a function".to_string(),
1341                    }
1342                })?;
1343
1344                let actual_type = match value {
1345                    Some(e) => self.check_expr(e, Some(&expected))?,
1346                    None => Type::Void,
1347                };
1348
1349                if !types_equal(&expected, &actual_type) {
1350                    return Err(AnalyserError::TypeError {
1351                        location: span.clone(),
1352                        message: format!(
1353                            "Function expects return type '{}', found '{}'",
1354                            type_to_string(&expected),
1355                            type_to_string(&actual_type)
1356                        ),
1357                    });
1358                }
1359
1360                Ok(())
1361            }
1362        }
1363    }
1364
1365    pub fn analyse(&mut self, program: &Program) -> Result<(), AnalyserError> {
1366        for stmt in &program.statements {
1367            self.check_stmt(stmt)?;
1368        }
1369        Ok(())
1370    }
1371}
1372impl Default for Analyser {
1373    fn default() -> Self {
1374        Self::new()
1375    }
1376}