Skip to main content

plc_ast/
ast.rs

1// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
2
3use std::{
4    fmt::{Debug, Display, Formatter},
5    hash::Hash,
6    ops::Range,
7};
8
9use derive_more::TryInto;
10use serde::{Deserialize, Serialize};
11
12use crate::{
13    control_statements::{
14        AstControlStatement, CaseStatement, ForLoopStatement, IfStatement, LoopStatement, ReturnStatement,
15    },
16    literals::{AstLiteral, StringValue},
17    pre_processor,
18    provider::IdProvider,
19    ser::AstSerializer,
20};
21
22use plc_source::source_location::*;
23
24pub type AstId = usize;
25
26#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub struct GenericBinding {
28    pub name: String,
29    pub nature: TypeNature,
30}
31
32#[derive(PartialEq, Serialize, Deserialize)]
33#[serde(bound(deserialize = "'de: 'static"))]
34pub struct Pou {
35    pub id: AstId,
36    pub name: String,
37    pub kind: PouType,
38    pub variable_blocks: Vec<VariableBlock>,
39    pub return_type: Option<DataTypeDeclaration>,
40    /// The SourceLocation of the whole POU
41    pub location: SourceLocation,
42    /// The SourceLocation of the POUs name
43    pub name_location: SourceLocation,
44    pub poly_mode: Option<PolymorphismMode>,
45    pub generics: Vec<GenericBinding>,
46    pub linkage: LinkageType,
47    pub super_class: Option<Identifier>,
48    pub is_const: bool,
49
50    /// A list of interfaces this POU implements
51    pub interfaces: Vec<Identifier>,
52
53    /// A list of properties this POU contains
54    pub properties: Vec<PropertyBlock>,
55}
56
57#[derive(Debug, PartialEq, Serialize, Deserialize)]
58#[serde(bound(deserialize = "'de: 'static"))]
59pub struct Interface {
60    pub id: AstId,
61    pub ident: Identifier,
62    pub location: SourceLocation,
63    pub methods: Vec<Pou>,
64    pub extensions: Vec<Identifier>,
65    pub properties: Vec<PropertyBlock>,
66}
67
68#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
69#[serde(bound(deserialize = "'de: 'static"))]
70pub struct Identifier {
71    pub name: String,
72    pub location: SourceLocation,
73}
74
75/// The property container as a whole, which contains [`PropertyImplementation`]s
76#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
77#[serde(bound(deserialize = "'de: 'static"))]
78pub struct PropertyBlock {
79    pub ident: Identifier,
80    pub implementations: Vec<PropertyImplementation>,
81}
82
83impl Eq for PropertyBlock {}
84
85impl Hash for PropertyBlock {
86    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
87        self.ident.hash(state);
88    }
89}
90
91#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
92#[serde(bound(deserialize = "'de: 'static"))]
93pub struct PropertyImplementation {
94    pub kind: PropertyKind,
95    pub datatype: DataTypeDeclaration,
96    pub location: SourceLocation,
97    pub variable_blocks: Vec<VariableBlock>,
98    pub body: Vec<AstNode>,
99    pub end_location: SourceLocation,
100}
101
102#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
103pub enum PropertyKind {
104    Get,
105    Set,
106}
107
108impl std::fmt::Display for PropertyKind {
109    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110        match self {
111            PropertyKind::Get => write!(f, "get"),
112            PropertyKind::Set => write!(f, "set"),
113        }
114    }
115}
116
117#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
118pub enum PolymorphismMode {
119    None,
120    Abstract,
121    Final,
122}
123
124#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
125#[serde(tag = "direction")]
126pub enum HardwareAccessType {
127    Input,
128    Output,
129    Memory,
130    Global,
131}
132
133#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
134#[serde(tag = "type")]
135pub enum DirectAccessType {
136    Bit,
137    Byte,
138    Word,
139    DWord,
140    LWord,
141    Template,
142}
143
144#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)]
145pub enum TypeNature {
146    Any,
147    Derived,
148    Elementary,
149    Magnitude,
150    Num,
151    Real,
152    Int,
153    Signed,
154    Unsigned,
155    Duration,
156    Bit,
157    Chars,
158    String,
159    Char,
160    Date,
161    __VLA,
162}
163
164impl TypeNature {
165    pub fn derives_from(self, other: TypeNature) -> bool {
166        if other == self {
167            true
168        } else {
169            match self {
170                TypeNature::Any => true,
171                TypeNature::Derived => matches!(other, TypeNature::Any),
172                TypeNature::__VLA => matches!(other, TypeNature::Any),
173                TypeNature::Elementary => matches!(other, TypeNature::Any),
174                TypeNature::Magnitude => matches!(other, TypeNature::Elementary | TypeNature::Any),
175                TypeNature::Num => {
176                    matches!(other, TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any)
177                }
178                TypeNature::Real => matches!(
179                    other,
180                    TypeNature::Num | TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any
181                ),
182                TypeNature::Int => matches!(
183                    other,
184                    TypeNature::Num | TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any
185                ),
186                TypeNature::Signed => matches!(
187                    other,
188                    TypeNature::Int
189                        | TypeNature::Num
190                        | TypeNature::Magnitude
191                        | TypeNature::Elementary
192                        | TypeNature::Any
193                ),
194                TypeNature::Unsigned => matches!(
195                    other,
196                    TypeNature::Int
197                        | TypeNature::Num
198                        | TypeNature::Magnitude
199                        | TypeNature::Elementary
200                        | TypeNature::Any
201                ),
202                TypeNature::Duration => {
203                    matches!(other, TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any)
204                }
205                TypeNature::Bit => matches!(other, TypeNature::Elementary | TypeNature::Any),
206                TypeNature::Chars => matches!(other, TypeNature::Elementary | TypeNature::Any),
207                TypeNature::String => {
208                    matches!(other, TypeNature::Chars | TypeNature::Elementary | TypeNature::Any)
209                }
210                TypeNature::Char => {
211                    matches!(other, TypeNature::Chars | TypeNature::Elementary | TypeNature::Any)
212                }
213                TypeNature::Date => matches!(other, TypeNature::Elementary | TypeNature::Any),
214            }
215        }
216    }
217
218    pub fn is_numerical(&self) -> bool {
219        self.derives_from(TypeNature::Num)
220    }
221
222    pub fn is_real(&self) -> bool {
223        self.derives_from(TypeNature::Real)
224    }
225
226    pub fn is_bit(&self) -> bool {
227        self.derives_from(TypeNature::Bit)
228    }
229}
230
231impl Display for TypeNature {
232    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
233        let name = match self {
234            TypeNature::Any => "ANY",
235            TypeNature::Derived => "ANY_DERIVED",
236            TypeNature::Elementary => "ANY_ELEMENTARY",
237            TypeNature::Magnitude => "ANY_MAGNITUDE",
238            TypeNature::Num => "ANY_NUMBER",
239            TypeNature::Real => "ANY_REAL",
240            TypeNature::Int => "ANY_INT",
241            TypeNature::Signed => "ANY_SIGNED",
242            TypeNature::Unsigned => "ANY_UNSIGNED",
243            TypeNature::Duration => "ANY_DURATION",
244            TypeNature::Bit => "ANY_BIT",
245            TypeNature::Chars => "ANY_CHARS",
246            TypeNature::String => "ANY_STRING",
247            TypeNature::Char => "ANY_CHAR",
248            TypeNature::Date => "ANY_DATE",
249            TypeNature::__VLA => "__ANY_VLA",
250        };
251        write!(f, "{name}")
252    }
253}
254
255impl DirectAccessType {
256    /// Returns the size of the bitaccess result
257    pub fn get_bit_width(&self) -> u64 {
258        match self {
259            DirectAccessType::Bit => 1,
260            DirectAccessType::Byte => 8,
261            DirectAccessType::Word => 16,
262            DirectAccessType::DWord => 32,
263            DirectAccessType::LWord => 64,
264            DirectAccessType::Template => unimplemented!("Should not test for template width"),
265        }
266    }
267}
268
269impl Debug for Pou {
270    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
271        let mut str = f.debug_struct("POU");
272        str.field("name", &self.name)
273            .field("variable_blocks", &self.variable_blocks)
274            .field("pou_type", &self.kind)
275            .field("return_type", &self.return_type)
276            .field("interfaces", &self.interfaces)
277            .field("properties", &self.properties);
278
279        if !self.generics.is_empty() {
280            str.field("generics", &self.generics);
281        }
282        str.finish()
283    }
284}
285
286impl Pou {
287    pub fn get_return_name(&self) -> &str {
288        Pou::calc_return_name(&self.name)
289    }
290
291    pub fn calc_return_name(pou_name: &str) -> &str {
292        pou_name.rsplit_once('.').map(|(_, return_name)| return_name).unwrap_or(pou_name)
293    }
294
295    pub fn is_aggregate(&self) -> bool {
296        matches!(self.return_type, Some(DataTypeDeclaration::Aggregate { .. }))
297    }
298
299    pub fn is_generic(&self) -> bool {
300        !self.generics.is_empty()
301    }
302
303    pub fn is_stateful(&self) -> bool {
304        matches!(self.kind, PouType::Program | PouType::FunctionBlock | PouType::Action | PouType::Class)
305    }
306
307    pub fn is_built_in(&self) -> bool {
308        self.linkage.is_built_in()
309    }
310
311    pub fn is_function_block(&self) -> bool {
312        matches!(self.kind, PouType::FunctionBlock)
313    }
314
315    pub fn is_class(&self) -> bool {
316        matches!(self.kind, PouType::Class)
317    }
318
319    pub fn is_program(&self) -> bool {
320        matches!(self.kind, PouType::Program)
321    }
322}
323
324#[derive(Debug, PartialEq, Serialize, Deserialize)]
325#[serde(bound(deserialize = "'de: 'static"))]
326pub struct Implementation {
327    pub name: String,
328    pub type_name: String,
329    pub linkage: LinkageType,
330    pub pou_type: PouType,
331    pub statements: Vec<AstNode>,
332    pub location: SourceLocation,
333    pub name_location: SourceLocation,
334    pub end_location: SourceLocation,
335    pub overriding: bool,
336    pub generic: bool,
337    pub access: Option<AccessModifier>,
338}
339
340#[derive(Debug, Copy, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
341pub enum LinkageType {
342    /// The element is declared in the project currently being complied
343    Internal,
344    /// The element is declared externally and being used by the project
345    External,
346    /// This indicates an element has been included as part of the library.
347    /// This is equivalant to external in almost all cases. The only difference is when code is
348    /// in constructor functions where an external function can get a constructor, while an
349    /// included function will not. See compile flag ´generate-external-constructors´
350    Include,
351    /// This indicates an element that should not have any declarations within the compiled project
352    /// For example a built in function is implied to exist but not declared
353    BuiltIn,
354}
355
356impl LinkageType {
357    pub fn is_external_or_included(&self) -> bool {
358        matches!(self, LinkageType::External | LinkageType::Include)
359    }
360
361    pub fn is_external(&self) -> bool {
362        matches!(self, LinkageType::External)
363    }
364
365    pub fn is_included(&self) -> bool {
366        matches!(self, LinkageType::Include)
367    }
368
369    pub fn is_built_in(&self) -> bool {
370        matches!(self, LinkageType::BuiltIn)
371    }
372}
373
374#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
375pub enum AccessModifier {
376    Private,
377    Public,
378    Protected, // default
379    Internal,
380}
381
382#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, Serialize, Deserialize)]
383pub enum DeclarationKind {
384    Abstract,
385    Concrete,
386}
387
388impl DeclarationKind {
389    pub fn is_abstract(&self) -> bool {
390        matches!(self, DeclarationKind::Abstract)
391    }
392
393    pub fn is_concrete(&self) -> bool {
394        matches!(self, DeclarationKind::Concrete)
395    }
396}
397
398#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
399pub enum PouType {
400    Program,
401    Function,
402    FunctionBlock,
403    Action,
404    Class,
405    Method {
406        /// The parent of this method, i.e. a function block, class or an interface
407        parent: String,
408
409        /// The property name (pre-mangled) and its type, if the method originated from a property
410        property: Option<(String, PropertyKind)>,
411
412        declaration_kind: DeclarationKind,
413    },
414    Init,
415    ProjectInit,
416}
417
418impl Display for PouType {
419    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
420        match self {
421            PouType::Program => write!(f, "Program"),
422            PouType::Function => write!(f, "Function"),
423            PouType::FunctionBlock => write!(f, "FunctionBlock"),
424            PouType::Action => write!(f, "Action"),
425            PouType::Class => write!(f, "Class"),
426            PouType::Method { .. } => write!(f, "Method"),
427            PouType::Init => write!(f, "Init"),
428            PouType::ProjectInit => write!(f, "ProjectInit"),
429        }
430    }
431}
432
433impl PouType {
434    /// returns Some(owner_class) if this is a `Method` or otherwhise `None`
435    pub fn get_optional_owner_class(&self) -> Option<String> {
436        if let PouType::Method { parent, .. } = self {
437            Some(parent.clone())
438        } else {
439            None
440        }
441    }
442
443    pub fn is_function_method_or_init(&self) -> bool {
444        matches!(self, PouType::Function | PouType::Init | PouType::ProjectInit | PouType::Method { .. })
445    }
446
447    pub fn is_stateful(&self) -> bool {
448        matches!(self, PouType::FunctionBlock | PouType::Program | PouType::Class)
449    }
450
451    pub fn is_class(&self) -> bool {
452        matches!(self, PouType::Class)
453    }
454
455    pub fn is_function_block(&self) -> bool {
456        matches!(self, PouType::FunctionBlock)
457    }
458}
459
460#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
461#[serde(bound(deserialize = "'de: 'static"))]
462pub struct ConfigVariable {
463    pub reference: AstNode,
464    pub data_type: DataTypeDeclaration,
465    pub address: AstNode,
466    pub location: SourceLocation,
467}
468
469impl ConfigVariable {
470    pub fn new(
471        reference: AstNode,
472        data_type: DataTypeDeclaration,
473        address: AstNode,
474        location: SourceLocation,
475    ) -> Self {
476        Self { reference, data_type, address, location }
477    }
478}
479
480#[derive(Debug, PartialEq, Serialize, Deserialize)]
481#[serde(bound(deserialize = "'de: 'static"))]
482pub struct CompilationUnit {
483    pub global_vars: Vec<VariableBlock>,
484    pub var_config: Vec<ConfigVariable>,
485    /// List of POU definitions (signature and some additional metadata)
486    pub pous: Vec<Pou>,
487    /// List of statements within a POU body
488    pub implementations: Vec<Implementation>,
489    pub interfaces: Vec<Interface>,
490    pub user_types: Vec<UserTypeDeclaration>,
491    pub file: FileMarker,
492    pub linkage: LinkageType,
493}
494
495impl CompilationUnit {
496    pub fn new(file_name: &'static str) -> Self {
497        CompilationUnit {
498            global_vars: Vec::new(),
499            var_config: Vec::new(),
500            pous: Vec::new(),
501            implementations: Vec::new(),
502            interfaces: Vec::new(),
503            user_types: Vec::new(),
504            file: FileMarker::File(file_name),
505            linkage: LinkageType::Internal,
506        }
507    }
508
509    pub fn with_implementations(mut self, implementations: Vec<Implementation>) -> Self {
510        self.implementations = implementations;
511        self
512    }
513
514    pub fn with_linkage(mut self, linkage: LinkageType) -> Self {
515        self.linkage = linkage;
516        self
517    }
518
519    /// imports all elements of the other CompilationUnit into this CompilationUnit
520    ///
521    /// this will import all global_vars, units, implementations and types. The imported
522    /// structs are moved from the other unit into this unit
523    /// # Arguments
524    /// `other` the other CompilationUnit to import the elements from.
525    pub fn import(&mut self, other: CompilationUnit) {
526        self.global_vars.extend(other.global_vars);
527        self.pous.extend(other.pous);
528        self.implementations.extend(other.implementations);
529        self.user_types.extend(other.user_types);
530    }
531}
532
533#[derive(Debug, Copy, PartialEq, Eq, Clone, Serialize, Deserialize)]
534pub enum VariableBlockType {
535    Local,
536    Temp,
537    Input(ArgumentProperty),
538    Output,
539    Global,
540    InOut,
541    External,
542}
543impl VariableBlockType {
544    pub fn is_temp(&self) -> bool {
545        matches!(self, VariableBlockType::Temp)
546    }
547
548    pub fn is_local(&self) -> bool {
549        matches!(self, VariableBlockType::Local)
550    }
551
552    pub fn is_global(&self) -> bool {
553        matches!(self, VariableBlockType::Global)
554    }
555
556    pub fn is_inout(&self) -> bool {
557        matches!(self, VariableBlockType::InOut)
558    }
559}
560
561impl Display for VariableBlockType {
562    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
563        match self {
564            VariableBlockType::Local => write!(f, "Local"),
565            VariableBlockType::Temp => write!(f, "Temp"),
566            VariableBlockType::Input(_) => write!(f, "Input"),
567            VariableBlockType::Output => write!(f, "Output"),
568            VariableBlockType::Global => write!(f, "Global"),
569            VariableBlockType::InOut => write!(f, "InOut"),
570            VariableBlockType::External => write!(f, "External"),
571        }
572    }
573}
574
575#[derive(Debug, Copy, PartialEq, Eq, Clone, Serialize, Deserialize)]
576pub enum ArgumentProperty {
577    ByVal,
578    ByRef,
579}
580
581#[derive(PartialEq, Clone, Serialize, Deserialize)]
582#[serde(bound(deserialize = "'de: 'static"))]
583pub struct VariableBlock {
584    pub access: AccessModifier,
585    pub constant: bool,
586    pub retain: bool,
587    pub variables: Vec<Variable>,
588    pub kind: VariableBlockType,
589    pub linkage: LinkageType,
590    pub location: SourceLocation,
591}
592
593impl VariableBlock {
594    pub fn global() -> Self {
595        VariableBlock::default().with_block_type(VariableBlockType::Global)
596    }
597
598    pub fn with_linkage(mut self, linkage: LinkageType) -> Self {
599        self.linkage = linkage;
600        self
601    }
602
603    pub fn with_block_type(mut self, block_type: VariableBlockType) -> Self {
604        self.kind = block_type;
605        self
606    }
607
608    pub fn with_variables(mut self, variables: Vec<Variable>) -> Self {
609        self.variables = variables;
610        self
611    }
612
613    pub fn is_local(&self) -> bool {
614        matches!(self.kind, VariableBlockType::Local)
615    }
616
617    pub fn is_temp(&self) -> bool {
618        matches!(self.kind, VariableBlockType::Temp)
619    }
620
621    pub fn is_input_by_val(&self) -> bool {
622        matches!(self.kind, VariableBlockType::Input(ArgumentProperty::ByVal))
623    }
624}
625
626impl Default for VariableBlock {
627    fn default() -> Self {
628        VariableBlock {
629            access: AccessModifier::Internal,
630            constant: false,
631            retain: false,
632            variables: vec![],
633            kind: VariableBlockType::Local,
634            linkage: LinkageType::Internal,
635            location: SourceLocation::internal(),
636        }
637    }
638}
639
640impl Debug for VariableBlock {
641    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
642        let mut result = f.debug_struct("VariableBlock");
643        result.field("variables", &self.variables).field("variable_block_type", &self.kind);
644
645        if self.constant {
646            result.field("constant", &self.constant);
647        }
648        if self.retain {
649            result.field("retain", &self.retain);
650        }
651        result.finish()
652    }
653}
654
655#[derive(Clone, Serialize, Deserialize)]
656#[serde(bound(deserialize = "'de: 'static"))]
657pub struct Variable {
658    pub name: String,
659    pub data_type_declaration: DataTypeDeclaration,
660    pub initializer: Option<AstNode>,
661    pub address: Option<AstNode>,
662    pub location: SourceLocation,
663}
664
665impl PartialEq for Variable {
666    fn eq(&self, other: &Self) -> bool {
667        self.name == other.name && self.location == other.location
668    }
669}
670
671impl Debug for Variable {
672    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
673        let mut var = f.debug_struct("Variable");
674        var.field("name", &self.name).field("data_type", &self.data_type_declaration);
675        if self.initializer.is_some() {
676            var.field("initializer", &self.initializer);
677        }
678        if self.address.is_some() {
679            var.field("address", &self.address);
680        }
681        var.finish()
682    }
683}
684
685impl Variable {
686    pub fn new(
687        name: impl Into<String>,
688        data_type_declaration: DataTypeDeclaration,
689        location: SourceLocation,
690    ) -> Variable {
691        Variable { name: name.into(), data_type_declaration, initializer: None, address: None, location }
692    }
693
694    pub fn replace_data_type_with_reference_to(&mut self, type_name: String) -> DataTypeDeclaration {
695        let new_data_type = DataTypeDeclaration::Reference {
696            referenced_type: type_name,
697            location: self.data_type_declaration.get_location(),
698        };
699        std::mem::replace(&mut self.data_type_declaration, new_data_type)
700    }
701
702    pub fn get_name(&self) -> &str {
703        &self.name
704    }
705}
706
707#[derive(Clone, PartialEq, Serialize, Deserialize)]
708#[serde(bound(deserialize = "'de: 'static"))]
709pub enum DataTypeDeclaration {
710    Reference { referenced_type: String, location: SourceLocation },
711    Definition { data_type: Box<DataType>, location: SourceLocation, scope: Option<String> },
712    Aggregate { referenced_type: String, location: SourceLocation },
713}
714
715impl Debug for DataTypeDeclaration {
716    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
717        match self {
718            DataTypeDeclaration::Reference { referenced_type, .. } => {
719                f.debug_struct("DataTypeReference").field("referenced_type", referenced_type).finish()
720            }
721            DataTypeDeclaration::Definition { data_type, .. } => {
722                f.debug_struct("DataTypeDefinition").field("data_type", data_type).finish()
723            }
724            DataTypeDeclaration::Aggregate { referenced_type, .. } => {
725                f.debug_struct("Aggregate").field("referenced_type", referenced_type).finish()
726            }
727        }
728    }
729}
730
731impl From<&DataTypeDeclaration> for SourceLocation {
732    fn from(value: &DataTypeDeclaration) -> Self {
733        value.get_location()
734    }
735}
736
737impl DataTypeDeclaration {
738    pub fn reference(referenced_type: impl Into<String>, location: SourceLocation) -> DataTypeDeclaration {
739        DataTypeDeclaration::Reference { referenced_type: referenced_type.into(), location }
740    }
741
742    pub fn get_name(&self) -> Option<&str> {
743        match self {
744            Self::Aggregate { referenced_type, .. }
745            | DataTypeDeclaration::Reference { referenced_type, .. } => Some(referenced_type.as_str()),
746            DataTypeDeclaration::Definition { data_type, .. } => data_type.get_name(),
747        }
748    }
749
750    pub fn get_location(&self) -> SourceLocation {
751        match self {
752            DataTypeDeclaration::Reference { location, .. } => location.clone(),
753            DataTypeDeclaration::Definition { location, .. } => location.clone(),
754            Self::Aggregate { location, .. } => location.clone(),
755        }
756    }
757
758    pub fn get_referenced_type(&self) -> Option<&str> {
759        let DataTypeDeclaration::Reference { referenced_type, .. } = self else { return None };
760        Some(referenced_type.as_str())
761    }
762
763    pub fn get_inner_pointer_ty(&self) -> Option<DataTypeDeclaration> {
764        match self {
765            DataTypeDeclaration::Reference { .. } => Some(self.clone()),
766
767            DataTypeDeclaration::Definition { data_type, .. } => {
768                if let DataType::PointerType { referenced_type, .. } = data_type.as_ref() {
769                    return referenced_type.get_inner_pointer_ty();
770                }
771
772                None
773            }
774            DataTypeDeclaration::Aggregate { .. } => None,
775        }
776    }
777
778    pub fn is_type_safe_pointer(&self) -> bool {
779        match self {
780            DataTypeDeclaration::Definition { data_type, .. } => data_type.is_type_safe_pointer(),
781            _ => false,
782        }
783    }
784
785    pub fn is_aggregate(&self) -> bool {
786        matches!(self, DataTypeDeclaration::Aggregate { .. })
787    }
788
789    pub fn is_reference_to(&self) -> bool {
790        matches!(
791            self,
792            DataTypeDeclaration::Definition {
793                data_type,
794                ..
795            } if matches!(
796                data_type.as_ref(),
797                DataType::PointerType {
798                    auto_deref: Some(AutoDerefType::Reference),
799                    ..
800                }
801            )
802        )
803    }
804}
805
806#[derive(PartialEq, Serialize, Deserialize)]
807#[serde(bound(deserialize = "'de: 'static"))]
808pub struct UserTypeDeclaration {
809    pub data_type: DataType,
810    pub initializer: Option<AstNode>,
811    pub location: SourceLocation,
812    /// stores the original scope for compiler-generated types
813    pub scope: Option<String>,
814    pub linkage: LinkageType,
815}
816
817impl Debug for UserTypeDeclaration {
818    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
819        f.debug_struct("UserTypeDeclaration")
820            .field("data_type", &self.data_type)
821            .field("initializer", &self.initializer)
822            .field("scope", &self.scope)
823            .finish()
824    }
825}
826
827#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
828#[serde(bound(deserialize = "'de: 'static"))]
829pub enum DataType {
830    StructType {
831        name: Option<String>, //maybe None for inline structs
832        variables: Vec<Variable>,
833    },
834    EnumType {
835        name: Option<String>, //maybe empty for inline enums
836        numeric_type: String,
837        elements: AstNode, //a single Ref, or an ExpressionList with Refs
838    },
839    SubRangeType {
840        name: Option<String>,
841        referenced_type: String,
842        /// Source location of `referenced_type`. Used by validation to point at
843        /// the actual offending token when the referenced type is unknown.
844        referenced_type_location: SourceLocation,
845        bounds: Option<AstNode>,
846    },
847    ArrayType {
848        name: Option<String>,
849        bounds: AstNode,
850        referenced_type: Box<DataTypeDeclaration>,
851        is_variable_length: bool,
852    },
853    PointerType {
854        name: Option<String>,
855        referenced_type: Box<DataTypeDeclaration>,
856        auto_deref: Option<AutoDerefType>,
857
858        /// Indicates whether to perform type validation. When false, pointer type mismatches are allowed,
859        /// e.g., `foo : POINTER TO DINT := ADR(stringValue)`. When true, the type of the pointer must match
860        /// the referenced type exactly.
861        type_safe: bool,
862
863        /// Indicates whether the pointer is a function pointer.
864        is_function: bool,
865    },
866    StringType {
867        name: Option<String>,
868        is_wide: bool, //WSTRING
869        size: Option<AstNode>,
870    },
871    VarArgs {
872        referenced_type: Option<Box<DataTypeDeclaration>>,
873        sized: bool, //If the variadic has the sized property
874    },
875    GenericType {
876        name: String,
877        generic_symbol: String,
878        nature: TypeNature,
879    },
880}
881
882#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
883pub enum AutoDerefType {
884    /// A plain pointer variable with the auto-deref trait, e.g. VAR_IN_OUT or VAR_INPUT{ref} variables
885    Default,
886
887    /// An alias pointer variable, e.g. `foo AT bar : DINT`
888    Alias,
889
890    /// A reference pointer variable, e.g. `foo : REFERENCE TO DINT;`
891    Reference,
892}
893
894impl DataType {
895    pub fn set_name(&mut self, new_name: String) {
896        match self {
897            DataType::StructType { name, .. }
898            | DataType::EnumType { name, .. }
899            | DataType::SubRangeType { name, .. }
900            | DataType::ArrayType { name, .. }
901            | DataType::PointerType { name, .. }
902            | DataType::StringType { name, .. } => *name = Some(new_name),
903            DataType::GenericType { name, .. } => *name = new_name,
904            DataType::VarArgs { .. } => {} //No names on varargs
905        }
906    }
907
908    pub fn get_name(&self) -> Option<&str> {
909        match &self {
910            DataType::StructType { name, .. }
911            | DataType::EnumType { name, .. }
912            | DataType::ArrayType { name, .. }
913            | DataType::PointerType { name, .. }
914            | DataType::StringType { name, .. }
915            | DataType::SubRangeType { name, .. } => name.as_ref().map(|x| x.as_str()),
916            DataType::GenericType { name, .. } => Some(name.as_str()),
917            DataType::VarArgs { referenced_type, .. } => {
918                referenced_type.as_ref().and_then(|it| DataTypeDeclaration::get_name(it.as_ref()))
919            }
920        }
921    }
922
923    //Attempts to replace the inner type with a reference. Returns the old type if replaceable
924    pub fn replace_data_type_with_reference_to(
925        &mut self,
926        type_name: String,
927        location: &SourceLocation,
928    ) -> Option<DataTypeDeclaration> {
929        match self {
930            DataType::ArrayType { referenced_type, .. } | DataType::PointerType { referenced_type, .. } => {
931                replace_reference(referenced_type, type_name, location)
932            }
933            _ => None,
934        }
935    }
936
937    pub fn is_pointer(&self) -> bool {
938        matches!(self, DataType::PointerType { .. })
939    }
940
941    pub fn is_type_safe_pointer(&self) -> bool {
942        matches!(self, DataType::PointerType { type_safe: true, .. })
943    }
944
945    pub fn is_generic(&self) -> bool {
946        matches!(self, DataType::GenericType { .. })
947    }
948}
949
950fn replace_reference(
951    referenced_type: &mut Box<DataTypeDeclaration>,
952    type_name: String,
953    location: &SourceLocation,
954) -> Option<DataTypeDeclaration> {
955    if let DataTypeDeclaration::Reference { .. } = **referenced_type {
956        return None;
957    }
958    let new_data_type =
959        DataTypeDeclaration::Reference { referenced_type: type_name, location: location.clone() };
960    let old_data_type = std::mem::replace(referenced_type, Box::new(new_data_type));
961    Some(*old_data_type)
962}
963
964#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
965#[serde(bound(deserialize = "'de: 'static"))]
966pub enum ReferenceAccess {
967    /// `.foo`
968    Global(Box<AstNode>),
969
970    /// a, a.b
971    Member(Box<AstNode>),
972
973    /// a[3]
974    Index(Box<AstNode>),
975
976    /// Color#Red
977    Cast(Box<AstNode>),
978
979    /// a^
980    Deref,
981
982    /// &a
983    Address,
984}
985
986// XXX: this should probably be an enum or dyn trait at some point, but for now we only have a singular use-case (preserving lowered AST for validation)
987// Another use-case might be markers to exclude internals from validation - this currently happens based on `SourceLocation` with `FileMarker`s,
988// this might be a better alternative
989#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
990#[serde(bound(deserialize = "'de: 'static"))]
991pub struct MetaData(Box<AstNode>);
992
993impl From<AstNode> for MetaData {
994    fn from(value: AstNode) -> Self {
995        Self(Box::new(value))
996    }
997}
998
999impl MetaData {
1000    pub fn get_inner(&self) -> &AstNode {
1001        self.0.as_ref()
1002    }
1003
1004    pub fn is_super(&self) -> bool {
1005        self.get_inner().is_super()
1006    }
1007
1008    pub fn is_super_deref(&self) -> bool {
1009        self.get_inner().is_super_deref()
1010    }
1011}
1012
1013#[derive(Clone, PartialEq, Serialize, Deserialize)]
1014#[serde(bound(deserialize = "'de: 'static"))]
1015pub struct AstNode {
1016    pub stmt: AstStatement,
1017    pub id: AstId,
1018    pub location: SourceLocation,
1019    pub metadata: Option<MetaData>,
1020}
1021
1022impl Default for AstNode {
1023    fn default() -> Self {
1024        AstFactory::create_empty_statement(SourceLocation::internal(), usize::MAX)
1025    }
1026}
1027
1028#[derive(Debug, Clone, PartialEq, TryInto, Serialize, Deserialize)]
1029#[serde(bound(deserialize = "'de: 'static"))]
1030#[try_into(ref, ref_mut, owned)]
1031pub enum AstStatement {
1032    EmptyStatement(EmptyStatement),
1033
1034    // A placeholder which indicates a default value of a datatype
1035    DefaultValue(DefaultValue),
1036
1037    // Literals
1038    Literal(AstLiteral),
1039    MultipliedStatement(MultipliedStatement),
1040
1041    // Expressions
1042    ReferenceExpr(ReferenceExpr),
1043    Identifier(String),
1044    Super(Option<DerefMarker>),
1045    This,
1046    DirectAccess(DirectAccess),
1047    HardwareAccess(HardwareAccess),
1048    BinaryExpression(BinaryExpression),
1049    UnaryExpression(UnaryExpression),
1050    ExpressionList(Vec<AstNode>),
1051    ParenExpression(Box<AstNode>),
1052    RangeStatement(RangeStatement),
1053    VlaRangeStatement,
1054
1055    // TODO: Merge these variants with a `kind` field?
1056    //       Update: Tried that, pattern matching becomes a pain in the ass; will probably be easier if we
1057    //               introduce a `get_inner` method to extract the enum variants or potentially wait for
1058    //               https://github.com/PLC-lang/rusty/pull/1221 to get merged
1059    // Assignments
1060    Assignment(Assignment),
1061    OutputAssignment(Assignment),
1062    RefAssignment(Assignment),
1063
1064    CallStatement(CallStatement),
1065
1066    // Control Statements
1067    ControlStatement(AstControlStatement),
1068    CaseCondition(Box<AstNode>),
1069    #[try_into(ignore)]
1070    ExitStatement(()),
1071    #[try_into(ignore)]
1072    ContinueStatement(()),
1073    ReturnStatement(ReturnStatement),
1074    JumpStatement(JumpStatement),
1075    LabelStatement(LabelStatement),
1076    AllocationStatement(Allocation),
1077}
1078
1079#[macro_export]
1080/// A `try_from` convenience wrapper for `AstNode`, passed as the `ex:expr` argument.
1081/// Will try to return a reference to the variants inner type, specified via the `t:ty` parameter.
1082/// Converts the `try_from`-`Result` into an `Option`
1083macro_rules! try_from {
1084    () => { None };
1085    ($ex:expr, $t:ty) => {
1086        <&$t>::try_from($ex.get_stmt()).ok()
1087    };
1088    ($($ex:tt)*, $t:ty) => {
1089        try_from!($($ex)*, $t).ok()
1090    };
1091}
1092
1093#[macro_export]
1094/// A `try_from` convenience wrapper for `AstNode`, passed as the `ex:expr` argument.
1095/// Will try to return a reference to the variants inner type, specified via the `t:ty` parameter.
1096/// Converts the `try_from`-`Result` into an `Option`
1097macro_rules! try_from_mut {
1098    () => { None };
1099    ($ex:expr, $t:ty) => {
1100        <&mut $t>::try_from($ex.get_stmt_mut()).ok()
1101    };
1102    ($($ex:tt)*, $t:ty) => {
1103        try_from_mut!($($ex)*, $t).ok()
1104    };
1105}
1106
1107impl Debug for AstNode {
1108    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1109        match &self.stmt {
1110            AstStatement::EmptyStatement(..) => f.debug_struct("EmptyStatement").finish(),
1111            AstStatement::DefaultValue(..) => f.debug_struct("DefaultValue").finish(),
1112            AstStatement::Literal(literal) => literal.fmt(f),
1113            AstStatement::Identifier(name) => f.debug_struct("Identifier").field("name", name).finish(),
1114            AstStatement::Super(Some(_)) => f.debug_struct("Super(derefed)").finish(),
1115            AstStatement::Super(_) => f.debug_struct("Super").finish(),
1116            AstStatement::This => f.debug_struct("This").finish(),
1117            AstStatement::BinaryExpression(BinaryExpression { operator, left, right }) => f
1118                .debug_struct("BinaryExpression")
1119                .field("operator", operator)
1120                .field("left", left)
1121                .field("right", right)
1122                .finish(),
1123            AstStatement::UnaryExpression(UnaryExpression { operator, value }) => {
1124                f.debug_struct("UnaryExpression").field("operator", operator).field("value", value).finish()
1125            }
1126            AstStatement::ExpressionList(expressions) => {
1127                f.debug_struct("ExpressionList").field("expressions", expressions).finish()
1128            }
1129            AstStatement::ParenExpression(expression) => {
1130                f.debug_struct("ParenExpression").field("expression", expression).finish()
1131            }
1132            AstStatement::RangeStatement(RangeStatement { start, end }) => {
1133                f.debug_struct("RangeStatement").field("start", start).field("end", end).finish()
1134            }
1135            AstStatement::VlaRangeStatement => f.debug_struct("VlaRangeStatement").finish(),
1136            AstStatement::Assignment(Assignment { left, right }) => {
1137                f.debug_struct("Assignment").field("left", left).field("right", right).finish()
1138            }
1139            AstStatement::OutputAssignment(Assignment { left, right }) => {
1140                f.debug_struct("OutputAssignment").field("left", left).field("right", right).finish()
1141            }
1142            AstStatement::RefAssignment(Assignment { left, right }) => {
1143                f.debug_struct("ReferenceAssignment").field("left", left).field("right", right).finish()
1144            }
1145            AstStatement::CallStatement(CallStatement { operator, parameters }) => f
1146                .debug_struct("CallStatement")
1147                .field("operator", operator)
1148                .field("parameters", parameters)
1149                .finish(),
1150            AstStatement::ControlStatement(
1151                AstControlStatement::If(IfStatement { blocks, else_block, .. }),
1152                ..,
1153            ) => {
1154                f.debug_struct("IfStatement").field("blocks", blocks).field("else_block", else_block).finish()
1155            }
1156            AstStatement::ControlStatement(
1157                AstControlStatement::ForLoop(ForLoopStatement { counter, start, end, by_step, body, .. }),
1158                ..,
1159            ) => f
1160                .debug_struct("ForLoopStatement")
1161                .field("counter", counter)
1162                .field("start", start)
1163                .field("end", end)
1164                .field("by_step", by_step)
1165                .field("body", body)
1166                .finish(),
1167            AstStatement::ControlStatement(
1168                AstControlStatement::WhileLoop(LoopStatement { condition, body, .. }),
1169                ..,
1170            ) => f
1171                .debug_struct("WhileLoopStatement")
1172                .field("condition", condition)
1173                .field("body", body)
1174                .finish(),
1175            AstStatement::ControlStatement(AstControlStatement::RepeatLoop(LoopStatement {
1176                condition,
1177                body,
1178                ..
1179            })) => f
1180                .debug_struct("RepeatLoopStatement")
1181                .field("condition", condition)
1182                .field("body", body)
1183                .finish(),
1184            AstStatement::ControlStatement(AstControlStatement::Case(CaseStatement {
1185                selector,
1186                case_blocks,
1187                else_block,
1188                ..
1189            })) => f
1190                .debug_struct("CaseStatement")
1191                .field("selector", selector)
1192                .field("case_blocks", case_blocks)
1193                .field("else_block", else_block)
1194                .finish(),
1195            AstStatement::DirectAccess(DirectAccess { access, index }) => {
1196                f.debug_struct("DirectAccess").field("access", access).field("index", index).finish()
1197            }
1198            AstStatement::HardwareAccess(HardwareAccess { direction, access, address }) => f
1199                .debug_struct("HardwareAccess")
1200                .field("direction", direction)
1201                .field("access", access)
1202                .field("address", address)
1203                .field("location", &self.location)
1204                .finish(),
1205            AstStatement::MultipliedStatement(MultipliedStatement { multiplier, element }, ..) => f
1206                .debug_struct("MultipliedStatement")
1207                .field("multiplier", multiplier)
1208                .field("element", element)
1209                .finish(),
1210            AstStatement::CaseCondition(condition) => {
1211                f.debug_struct("CaseCondition").field("condition", condition).finish()
1212            }
1213            AstStatement::ReturnStatement(ReturnStatement { condition }) => {
1214                f.debug_struct("ReturnStatement").field("condition", condition).finish()
1215            }
1216            AstStatement::ContinueStatement(..) => f.debug_struct("ContinueStatement").finish(),
1217            AstStatement::ExitStatement(..) => f.debug_struct("ExitStatement").finish(),
1218            AstStatement::ReferenceExpr(ReferenceExpr { access, base }) => {
1219                f.debug_struct("ReferenceExpr").field("kind", access).field("base", base).finish()
1220            }
1221            AstStatement::JumpStatement(JumpStatement { condition, target, .. }) => {
1222                f.debug_struct("JumpStatement").field("condition", condition).field("target", target).finish()
1223            }
1224            AstStatement::LabelStatement(LabelStatement { name, .. }) => {
1225                f.debug_struct("LabelStatement").field("name", name).finish()
1226            }
1227            AstStatement::AllocationStatement(Allocation { name, reference_type, statement_scoped }) => {
1228                let mut out = f.debug_struct("Allocation");
1229                out.field("name", name).field("reference_type", reference_type);
1230                // Only surface the exceptional pinned case; the common statement-scoped
1231                // allocation keeps its compact debug output.
1232                if !statement_scoped {
1233                    out.field("statement_scoped", statement_scoped);
1234                }
1235                out.finish()
1236            }
1237        }
1238    }
1239}
1240
1241impl From<&AstNode> for SourceLocation {
1242    fn from(value: &AstNode) -> Self {
1243        value.get_location()
1244    }
1245}
1246
1247impl AstNode {
1248    ///Returns the statement in a singleton list, or the contained statements if the statement is already a list
1249    pub fn get_as_list(&self) -> Vec<&AstNode> {
1250        try_from!(self, Vec<AstNode>).map(|it| it.iter().collect()).unwrap_or(vec![self])
1251    }
1252
1253    pub fn get_location(&self) -> SourceLocation {
1254        self.location.clone()
1255    }
1256
1257    pub fn set_location(&mut self, location: SourceLocation) {
1258        self.location = location;
1259    }
1260
1261    pub fn get_id(&self) -> AstId {
1262        self.id
1263    }
1264
1265    pub fn get_stmt(&self) -> &AstStatement {
1266        &self.stmt
1267    }
1268
1269    pub fn get_stmt_mut(&mut self) -> &mut AstStatement {
1270        &mut self.stmt
1271    }
1272
1273    /// Similar to [`AstNode::get_stmt`] with the exception of peeling parenthesized expressions.
1274    /// For example if called on `((1))` this function would return a [`AstStatement::Literal`] ignoring the
1275    /// parenthesized expressions altogether.
1276    pub fn get_stmt_peeled(&self) -> &AstStatement {
1277        match &self.stmt {
1278            AstStatement::ParenExpression(expr) => expr.get_stmt_peeled(),
1279            _ => &self.stmt,
1280        }
1281    }
1282
1283    /// Returns true if this node represents a struct literal initializer,
1284    /// i.e. a (possibly parenthesized) expression list or named assignment
1285    /// like `(a := 1, b := 2)` or `(field := value)`.
1286    pub fn is_struct_literal_initializer(&self) -> bool {
1287        matches!(self.get_stmt_peeled(), AstStatement::ExpressionList(_) | AstStatement::Assignment(_))
1288    }
1289
1290    pub fn get_node_peeled(&self) -> &AstNode {
1291        match &self.stmt {
1292            AstStatement::ParenExpression(expr) => expr.get_node_peeled(),
1293            _ => self,
1294        }
1295    }
1296
1297    pub fn get_metadata(&self) -> Option<&MetaData> {
1298        self.get_node_peeled().metadata.as_ref()
1299    }
1300
1301    /// Returns true if the current statement has a direct access.
1302    pub fn has_direct_access(&self) -> bool {
1303        match &self.stmt {
1304            AstStatement::ReferenceExpr(
1305                ReferenceExpr { access: ReferenceAccess::Member(reference), base },
1306                ..,
1307            )
1308            | AstStatement::ReferenceExpr(
1309                ReferenceExpr { access: ReferenceAccess::Cast(reference), base },
1310                ..,
1311            ) => {
1312                reference.has_direct_access()
1313                    || base.as_ref().map(|it| it.has_direct_access()).unwrap_or(false)
1314            }
1315            AstStatement::DirectAccess(..) => true,
1316            _ => false,
1317        }
1318    }
1319
1320    /// returns true if this AST Statement is a literal or reference that can be
1321    /// prefixed with a type-cast (e.g. INT#23)
1322    pub fn is_cast_prefix_eligible(&self) -> bool {
1323        // TODO: figure out a better name for this...
1324        match &self.stmt {
1325            AstStatement::Literal(kind, ..) => kind.is_cast_prefix_eligible(),
1326            AstStatement::Identifier(..) => true,
1327            _ => false,
1328        }
1329    }
1330
1331    /// Returns true if the current statement is a flat reference (e.g. `a`)
1332    pub fn is_flat_reference(&self) -> bool {
1333        self.get_flat_reference_name().is_some()
1334    }
1335
1336    /// Returns the reference-name if this is a flat reference like `a`, or None if this is no flat reference
1337    pub fn get_flat_reference_name(&self) -> Option<&str> {
1338        match &self.stmt {
1339            AstStatement::Identifier(name, ..) => Some(name),
1340            AstStatement::ReferenceExpr(ReferenceExpr {
1341                access: ReferenceAccess::Member(reference) | ReferenceAccess::Global(reference),
1342                ..
1343            }) => reference.as_ref().get_flat_reference_name(),
1344            _ => None,
1345        }
1346    }
1347
1348    pub fn get_parent_name_of_reference(&self) -> Option<&str> {
1349        if let AstStatement::ReferenceExpr(ReferenceExpr { base: Some(base), .. }, ..) = &self.stmt {
1350            base.as_ref().get_flat_reference_name()
1351        } else {
1352            None
1353        }
1354    }
1355
1356    pub fn get_label_name(&self) -> Option<&str> {
1357        match &self.stmt {
1358            AstStatement::LabelStatement(LabelStatement { name, .. }) => Some(name.as_str()),
1359            _ => None,
1360        }
1361    }
1362
1363    pub fn is_empty_statement(&self) -> bool {
1364        matches!(self.stmt, AstStatement::EmptyStatement(..))
1365    }
1366
1367    pub fn is_assignment(&self) -> bool {
1368        matches!(self.stmt, AstStatement::Assignment(..))
1369    }
1370
1371    pub fn is_output_assignment(&self) -> bool {
1372        matches!(self.stmt, AstStatement::OutputAssignment(..))
1373    }
1374
1375    pub fn is_reference(&self) -> bool {
1376        matches!(self.stmt, AstStatement::ReferenceExpr(..))
1377    }
1378
1379    pub fn is_member_access(&self) -> bool {
1380        matches!(
1381            self.stmt,
1382            AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Member(..), .. }, ..)
1383        )
1384    }
1385
1386    pub fn get_initial_base(&self) -> Option<&AstNode> {
1387        match &self.stmt {
1388            AstStatement::ReferenceExpr(ReferenceExpr { base, .. }, ..) => {
1389                if base.is_none() {
1390                    return Some(self);
1391                }
1392                base.as_ref().and_then(|it| it.get_initial_base())
1393            }
1394            AstStatement::Identifier(_) => Some(self),
1395            _ => None,
1396        }
1397    }
1398
1399    pub fn get_identifier(&self) -> Option<&AstNode> {
1400        if self.is_identifier() {
1401            return Some(self);
1402        }
1403        match &self.stmt {
1404            AstStatement::ReferenceExpr(
1405                ReferenceExpr { access: ReferenceAccess::Member(reference), .. },
1406                ..,
1407            ) => reference.get_identifier(),
1408            _ => None,
1409        }
1410    }
1411
1412    pub fn is_call(&self) -> bool {
1413        matches!(self.stmt, AstStatement::CallStatement(..))
1414    }
1415
1416    pub fn is_hardware_access(&self) -> bool {
1417        matches!(self.stmt, AstStatement::HardwareAccess(..))
1418    }
1419
1420    pub fn is_array_access(&self) -> bool {
1421        matches!(
1422            self.stmt,
1423            AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Index(_), .. }, ..)
1424        )
1425    }
1426
1427    pub fn is_pointer_access(&self) -> bool {
1428        matches!(
1429            self.stmt,
1430            AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Deref, .. }, ..)
1431        )
1432    }
1433
1434    pub fn is_this(&self) -> bool {
1435        matches!(self.stmt, AstStatement::This)
1436    }
1437
1438    pub fn is_this_deref(&self) -> bool {
1439        match &self.stmt {
1440            AstStatement::ReferenceExpr(
1441                ReferenceExpr { access: ReferenceAccess::Deref, base: Some(base) },
1442                ..,
1443            ) => base.is_this(),
1444
1445            _ => false,
1446        }
1447    }
1448
1449    pub fn is_paren(&self) -> bool {
1450        matches!(self.stmt, AstStatement::ParenExpression { .. })
1451    }
1452
1453    pub fn is_expression_list(&self) -> bool {
1454        matches!(self.stmt, AstStatement::ExpressionList { .. })
1455    }
1456
1457    pub fn is_super(&self) -> bool {
1458        let node = match &self.stmt {
1459            AstStatement::ReferenceExpr(
1460                ReferenceExpr { access: ReferenceAccess::Member(reference), .. },
1461                ..,
1462            ) => reference,
1463            _ => self,
1464        };
1465        matches!(node.get_stmt_peeled(), AstStatement::Super(..))
1466    }
1467
1468    pub fn is_super_deref(&self) -> bool {
1469        let node = match &self.stmt {
1470            AstStatement::ReferenceExpr(
1471                ReferenceExpr { access: ReferenceAccess::Member(reference), .. },
1472                ..,
1473            ) => reference,
1474            _ => self,
1475        };
1476        matches!(node.get_stmt_peeled(), AstStatement::Super(Some(_)))
1477    }
1478
1479    pub fn is_super_or_super_deref(&self) -> bool {
1480        self.is_super() || self.is_super_deref()
1481    }
1482
1483    pub fn has_super_metadata(&self) -> bool {
1484        self.get_metadata()
1485            .or_else(|| self.get_identifier().and_then(|it| it.get_metadata()))
1486            .is_some_and(|it| it.is_super())
1487    }
1488
1489    pub fn has_super_metadata_deref(&self) -> bool {
1490        self.get_metadata()
1491            .or_else(|| self.get_identifier().and_then(|it| it.get_metadata()))
1492            .is_some_and(|it| it.is_super_deref())
1493    }
1494
1495    pub fn can_be_assigned_to(&self) -> bool {
1496        if self.has_super_metadata() {
1497            return false;
1498        }
1499        if self.is_this() {
1500            return false;
1501        }
1502        self.has_direct_access()
1503            || self.is_flat_reference()
1504            || self.is_reference()
1505            || self.is_array_access()
1506            || self.is_pointer_access()
1507            || self.is_hardware_access()
1508    }
1509
1510    pub fn new(stmt: AstStatement, id: AstId, location: impl Into<SourceLocation>) -> AstNode {
1511        AstNode { stmt, id, location: location.into(), metadata: None }
1512    }
1513
1514    pub fn new_literal(kind: AstLiteral, id: AstId, location: SourceLocation) -> AstNode {
1515        AstNode::new(AstStatement::Literal(kind), id, location)
1516    }
1517
1518    pub fn new_integer(value: i128, id: AstId, location: SourceLocation) -> AstNode {
1519        AstNode::new(AstStatement::Literal(AstLiteral::Integer(value)), id, location)
1520    }
1521
1522    pub fn new_real(value: String, id: AstId, location: SourceLocation) -> AstNode {
1523        AstNode::new(AstStatement::Literal(AstLiteral::Real(value)), id, location)
1524    }
1525
1526    pub fn new_string(
1527        value: impl Into<String>,
1528        is_wide: bool,
1529        id: AstId,
1530        location: SourceLocation,
1531    ) -> AstNode {
1532        AstNode::new(
1533            AstStatement::Literal(AstLiteral::String(StringValue { value: value.into(), is_wide })),
1534            id,
1535            location,
1536        )
1537    }
1538
1539    /// Returns true if the given token is an integer or float and zero.
1540    pub fn is_zero(&self) -> bool {
1541        try_from!(self, AstLiteral).is_some_and(|it| it.is_zero())
1542    }
1543
1544    pub fn is_binary_expression(&self) -> bool {
1545        matches!(self.stmt, AstStatement::BinaryExpression(..))
1546    }
1547
1548    pub fn is_literal_array(&self) -> bool {
1549        matches!(self.stmt, AstStatement::Literal(AstLiteral::Array(..), ..))
1550    }
1551
1552    pub fn is_literal(&self) -> bool {
1553        matches!(self.stmt, AstStatement::Literal(..))
1554    }
1555
1556    pub fn is_literal_integer(&self) -> bool {
1557        matches!(self.stmt, AstStatement::Literal(AstLiteral::Integer(..), ..))
1558    }
1559
1560    pub fn get_literal_integer_value(&self) -> Option<i128> {
1561        try_from!(self, AstLiteral).map(|it| it.get_literal_integer_value()).unwrap_or_default()
1562    }
1563
1564    pub fn is_identifier(&self) -> bool {
1565        matches!(self.stmt, AstStatement::Identifier(..))
1566    }
1567
1568    pub fn is_default_value(&self) -> bool {
1569        matches!(self.stmt, AstStatement::DefaultValue { .. })
1570    }
1571
1572    /// Negates the given element by adding it to a not expression
1573    pub fn negate(self: AstNode, mut id_provider: IdProvider) -> AstNode {
1574        let location = self.get_location();
1575        AstFactory::create_not_expression(self, location, id_provider.next_id())
1576    }
1577
1578    pub fn is_template(&self) -> bool {
1579        matches!(
1580            self.stmt,
1581            AstStatement::HardwareAccess(HardwareAccess { access: DirectAccessType::Template, .. })
1582        )
1583    }
1584
1585    pub fn with_metadata(self, metadata: MetaData) -> AstNode {
1586        AstNode { metadata: Some(metadata), ..self }
1587    }
1588
1589    pub fn is_deref(&self) -> bool {
1590        matches!(
1591            self,
1592            AstNode {
1593                stmt: AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Deref, .. }),
1594                ..
1595            }
1596        )
1597    }
1598
1599    pub fn get_call_operator(&self) -> Option<&AstNode> {
1600        match &self.stmt {
1601            AstStatement::CallStatement(CallStatement { operator, .. }) => Some(operator),
1602            _ => None,
1603        }
1604    }
1605
1606    pub fn get_ref_expr_mut(&mut self) -> Option<&mut ReferenceExpr> {
1607        match &mut self.stmt {
1608            AstStatement::ReferenceExpr(expr) => Some(expr),
1609            _ => None,
1610        }
1611    }
1612
1613    pub fn get_deref_expr(&self) -> Option<&ReferenceExpr> {
1614        match &self.stmt {
1615            AstStatement::ReferenceExpr(expr) => match expr {
1616                ReferenceExpr { access: ReferenceAccess::Deref, .. } => Some(expr),
1617                _ => None,
1618            },
1619            _ => None,
1620        }
1621    }
1622
1623    pub fn get_base_ref_expr(&self) -> Option<&AstNode> {
1624        match &self.stmt {
1625            AstStatement::ReferenceExpr(ReferenceExpr { base: Some(base), .. }) => Some(base.as_ref()),
1626            _ => None,
1627        }
1628    }
1629
1630    pub fn get_base_ref_expr_mut(&mut self) -> Option<&mut AstNode> {
1631        match &mut self.stmt {
1632            AstStatement::ReferenceExpr(ReferenceExpr { base: Some(base), .. }) => Some(base.as_mut()),
1633            _ => None,
1634        }
1635    }
1636
1637    pub fn as_string(&self) -> String {
1638        AstSerializer::format(self)
1639    }
1640
1641    pub fn is_real(&self) -> bool {
1642        matches!(self.stmt, AstStatement::Literal(AstLiteral::Real(_), ..))
1643    }
1644
1645    /// Returns the identifier of the left-hand side if this is an assignment statement
1646    pub fn get_assignment_identifier(&self) -> Option<&str> {
1647        match &self.stmt {
1648            AstStatement::Assignment(Assignment { left, .. })
1649            | AstStatement::OutputAssignment(Assignment { left, .. })
1650            | AstStatement::RefAssignment(Assignment { left, .. }) => left.get_flat_reference_name(),
1651            _ => None,
1652        }
1653    }
1654}
1655
1656#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1657pub enum Operator {
1658    Plus,
1659    Minus,
1660    Multiplication,
1661    Exponentiation,
1662    Division,
1663    Equal,
1664    NotEqual,
1665    Modulo,
1666    Less,
1667    Greater,
1668    LessOrEqual,
1669    GreaterOrEqual,
1670    Not,
1671    And,
1672    Or,
1673    Xor,
1674    AndThen,
1675    OrElse,
1676}
1677
1678impl Display for Operator {
1679    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1680        let symbol = match self {
1681            Operator::Plus => "+",
1682            Operator::Minus => "-",
1683            Operator::Multiplication => "*",
1684            Operator::Division => "/",
1685            Operator::Equal => "=",
1686            Operator::NotEqual => "<>",
1687            Operator::Modulo => "MOD",
1688            Operator::Less => "<",
1689            Operator::Greater => ">",
1690            Operator::LessOrEqual => "<=",
1691            Operator::GreaterOrEqual => ">=",
1692            Operator::Not => "NOT",
1693            Operator::And => "AND",
1694            Operator::Or => "OR",
1695            Operator::Xor => "XOR",
1696            Operator::AndThen => "AND_THEN",
1697            Operator::OrElse => "OR_ELSE",
1698            Operator::Exponentiation => "**",
1699        };
1700        f.write_str(symbol)
1701    }
1702}
1703
1704/// enum_elements should be the statement between then enum's brackets ( )
1705/// e.g. x : ( this, that, etc)
1706pub fn get_enum_element_names(enum_elements: &AstNode) -> Vec<String> {
1707    flatten_expression_list(enum_elements)
1708        .into_iter()
1709        .filter(|it| matches!(it.stmt, AstStatement::Identifier(..) | AstStatement::Assignment(..)))
1710        .map(get_enum_element_name)
1711        .collect()
1712}
1713
1714/// expects a Reference or an Assignment
1715pub fn get_enum_element_name(enum_element: &AstNode) -> String {
1716    match &enum_element.stmt {
1717        AstStatement::Identifier(name, ..) => name.to_string(),
1718        AstStatement::Assignment(Assignment { left, .. }, ..) => left
1719            .get_flat_reference_name()
1720            .map(|it| it.to_string())
1721            .expect("left of assignment not a reference"),
1722        _ => {
1723            unreachable!("expected {:?} to be a Reference or Assignment", enum_element);
1724        }
1725    }
1726}
1727
1728/// flattens expression-lists and MultipliedStatements into a vec of statements.
1729/// It can also handle nested structures like 2(3(4,5))
1730pub fn flatten_expression_list(list: &AstNode) -> Vec<&AstNode> {
1731    match &list.stmt {
1732        AstStatement::ExpressionList(expressions, ..) => {
1733            expressions.iter().by_ref().flat_map(flatten_expression_list).collect()
1734        }
1735        AstStatement::MultipliedStatement(MultipliedStatement { multiplier, element }, ..) => {
1736            std::iter::repeat_n(flatten_expression_list(element), *multiplier as usize).flatten().collect()
1737        }
1738        AstStatement::ParenExpression(expression) => flatten_expression_list(expression),
1739        _ => vec![list],
1740    }
1741}
1742
1743pub fn steal_expression_list(list: &mut AstNode) -> Vec<AstNode> {
1744    match &mut list.stmt {
1745        AstStatement::ExpressionList(expressions, ..) => std::mem::take(expressions),
1746        AstStatement::ParenExpression(expression) => steal_expression_list(expression),
1747        _ => {
1748            let node = std::mem::take(list);
1749            vec![node]
1750        }
1751    }
1752}
1753
1754pub fn pre_process(unit: &mut CompilationUnit, id_provider: IdProvider) {
1755    pre_processor::pre_process(unit, id_provider)
1756}
1757impl Operator {
1758    /// returns true, if this operator is a comparison operator,
1759    /// resulting in a bool value
1760    /// (=, <>, >, <, >=, <=)
1761    pub fn is_comparison_operator(&self) -> bool {
1762        matches!(
1763            self,
1764            Operator::Equal
1765                | Operator::NotEqual
1766                | Operator::Less
1767                | Operator::Greater
1768                | Operator::LessOrEqual
1769                | Operator::GreaterOrEqual
1770        )
1771    }
1772}
1773
1774#[cfg(test)]
1775mod tests {
1776    use crate::ast::{ArgumentProperty, DeclarationKind, PouType, VariableBlockType};
1777
1778    #[test]
1779    fn display_pou() {
1780        assert_eq!(PouType::Program.to_string(), "Program");
1781        assert_eq!(PouType::Function.to_string(), "Function");
1782        assert_eq!(PouType::FunctionBlock.to_string(), "FunctionBlock");
1783        assert_eq!(PouType::Action.to_string(), "Action");
1784        assert_eq!(PouType::Class.to_string(), "Class");
1785        assert_eq!(
1786            PouType::Method {
1787                parent: String::new(),
1788                property: None,
1789                declaration_kind: DeclarationKind::Concrete
1790            }
1791            .to_string(),
1792            "Method"
1793        );
1794    }
1795
1796    #[test]
1797    fn display_variable_block_type() {
1798        assert_eq!(VariableBlockType::Local.to_string(), "Local");
1799        assert_eq!(VariableBlockType::Temp.to_string(), "Temp");
1800        assert_eq!(VariableBlockType::Input(ArgumentProperty::ByVal).to_string(), "Input");
1801        assert_eq!(VariableBlockType::Input(ArgumentProperty::ByRef).to_string(), "Input");
1802        assert_eq!(VariableBlockType::Output.to_string(), "Output");
1803        assert_eq!(VariableBlockType::Global.to_string(), "Global");
1804        assert_eq!(VariableBlockType::InOut.to_string(), "InOut");
1805    }
1806}
1807
1808pub struct AstFactory {}
1809
1810impl AstFactory {
1811    pub fn create_empty_statement(location: SourceLocation, id: AstId) -> AstNode {
1812        AstNode { stmt: AstStatement::EmptyStatement(EmptyStatement {}), location, id, metadata: None }
1813    }
1814
1815    pub fn create_return_statement(
1816        condition: Option<AstNode>,
1817        location: SourceLocation,
1818        id: AstId,
1819    ) -> AstNode {
1820        let condition = condition.map(Box::new);
1821        AstNode::new(AstStatement::ReturnStatement(ReturnStatement { condition }), id, location)
1822    }
1823
1824    pub fn create_exit_statement(location: SourceLocation, id: AstId) -> AstNode {
1825        AstNode::new(AstStatement::ExitStatement(()), id, location)
1826    }
1827
1828    pub fn create_continue_statement(location: SourceLocation, id: AstId) -> AstNode {
1829        AstNode::new(AstStatement::ContinueStatement(()), id, location)
1830    }
1831
1832    pub fn create_case_condition(result: AstNode, location: SourceLocation, id: AstId) -> AstNode {
1833        AstNode::new(AstStatement::CaseCondition(Box::new(result)), id, location)
1834    }
1835
1836    pub fn create_vla_range_statement(location: SourceLocation, id: AstId) -> AstNode {
1837        AstNode::new(AstStatement::VlaRangeStatement, id, location)
1838    }
1839
1840    pub fn create_literal(kind: AstLiteral, location: SourceLocation, id: AstId) -> AstNode {
1841        AstNode::new(AstStatement::Literal(kind), id, location)
1842    }
1843
1844    pub fn create_hardware_access(
1845        access: DirectAccessType,
1846        direction: HardwareAccessType,
1847        address: Vec<AstNode>,
1848        location: SourceLocation,
1849        id: usize,
1850    ) -> AstNode {
1851        AstNode::new(
1852            AstStatement::HardwareAccess(HardwareAccess { access, direction, address }),
1853            id,
1854            location,
1855        )
1856    }
1857
1858    pub fn create_default_value(location: SourceLocation, id: AstId) -> AstNode {
1859        AstNode::new(AstStatement::DefaultValue(DefaultValue {}), id, location)
1860    }
1861
1862    pub fn create_expression_list(expressions: Vec<AstNode>, location: SourceLocation, id: AstId) -> AstNode {
1863        AstNode::new(AstStatement::ExpressionList(expressions), id, location)
1864    }
1865
1866    pub fn create_paren_expression(expression: AstNode, location: SourceLocation, id: AstId) -> AstNode {
1867        AstNode::new(AstStatement::ParenExpression(Box::new(expression)), id, location)
1868    }
1869
1870    /// creates a new if-statement
1871    pub fn create_if_statement(stmt: IfStatement, location: SourceLocation, id: AstId) -> AstNode {
1872        AstNode::new(AstStatement::ControlStatement(AstControlStatement::If(stmt)), id, location)
1873    }
1874
1875    ///  creates a new for loop statement
1876    pub fn create_for_loop(stmt: ForLoopStatement, location: SourceLocation, id: AstId) -> AstNode {
1877        AstNode::new(AstStatement::ControlStatement(AstControlStatement::ForLoop(stmt)), id, location)
1878    }
1879
1880    /// creates a new while statement
1881    pub fn create_while_statement(stmt: LoopStatement, location: SourceLocation, id: AstId) -> AstNode {
1882        AstNode::new(AstStatement::ControlStatement(AstControlStatement::WhileLoop(stmt)), id, location)
1883    }
1884
1885    /// creates a new repeat-statement
1886    pub fn create_repeat_statement(stmt: LoopStatement, location: SourceLocation, id: AstId) -> AstNode {
1887        AstNode::new(AstStatement::ControlStatement(AstControlStatement::RepeatLoop(stmt)), id, location)
1888    }
1889
1890    /// creates a new case-statement
1891    pub fn create_case_statement(stmt: CaseStatement, location: SourceLocation, id: AstId) -> AstNode {
1892        AstNode::new(AstStatement::ControlStatement(AstControlStatement::Case(stmt)), id, location)
1893    }
1894
1895    /// creates an or-expression
1896    pub fn create_or_expression(left: AstNode, right: AstNode) -> AstNode {
1897        let id = left.get_id();
1898        let location = left.get_location().span(&right.get_location());
1899        AstNode::new(
1900            AstStatement::BinaryExpression(BinaryExpression {
1901                left: Box::new(left),
1902                right: Box::new(right),
1903                operator: Operator::Or,
1904            }),
1905            id,
1906            location,
1907        )
1908    }
1909
1910    /// creates a not-expression
1911    pub fn create_not_expression(operator: AstNode, location: SourceLocation, id: usize) -> AstNode {
1912        AstNode::new(
1913            AstStatement::UnaryExpression(UnaryExpression {
1914                value: Box::new(operator),
1915                operator: Operator::Not,
1916            }),
1917            id,
1918            location,
1919        )
1920    }
1921
1922    /// creates a new Identifier
1923    pub fn create_identifier<T, U>(name: T, location: U, id: AstId) -> AstNode
1924    where
1925        T: Into<String>,
1926        U: Into<SourceLocation>,
1927    {
1928        AstNode::new(AstStatement::Identifier(name.into()), id, location.into())
1929    }
1930
1931    pub fn create_super_reference<T>(location: T, deref: Option<DerefMarker>, id: AstId) -> AstNode
1932    where
1933        T: Into<SourceLocation>,
1934    {
1935        AstNode::new(AstStatement::Super(deref), id, location.into())
1936    }
1937
1938    pub fn create_this_reference<T>(location: T, id: AstId) -> AstNode
1939    where
1940        T: Into<SourceLocation>,
1941    {
1942        AstNode::new(AstStatement::This, id, location.into())
1943    }
1944
1945    pub fn create_unary_expression(
1946        operator: Operator,
1947        value: AstNode,
1948        location: SourceLocation,
1949        id: AstId,
1950    ) -> AstNode {
1951        AstNode::new(
1952            AstStatement::UnaryExpression(UnaryExpression { operator, value: Box::new(value) }),
1953            id,
1954            location,
1955        )
1956    }
1957
1958    pub fn create_assignment(left: AstNode, right: AstNode, id: AstId) -> AstNode {
1959        let location = left.location.span(&right.location);
1960        AstNode::new(
1961            AstStatement::Assignment(Assignment { left: Box::new(left), right: Box::new(right) }),
1962            id,
1963            location,
1964        )
1965    }
1966
1967    pub fn create_output_assignment(left: AstNode, right: AstNode, id: AstId) -> AstNode {
1968        let location = left.location.span(&right.location);
1969        AstNode::new(
1970            AstStatement::OutputAssignment(Assignment { left: Box::new(left), right: Box::new(right) }),
1971            id,
1972            location,
1973        )
1974    }
1975
1976    // TODO: Merge `create_assignment`, `create_output_assignment` and `create_ref_assignment`
1977    //       once the the Assignment AstStatements have been merged and a `kind` field is available
1978    //       I.e. something like `AstStatement::Assignment { data, kind: AssignmentKind { Normal, Output, Reference } }
1979    //       and then fn create_assignment(kind: AssignmentKind, ...)
1980    pub fn create_ref_assignment(left: AstNode, right: AstNode, id: AstId) -> AstNode {
1981        let location = left.location.span(&right.location);
1982        AstNode::new(
1983            AstStatement::RefAssignment(Assignment { left: Box::new(left), right: Box::new(right) }),
1984            id,
1985            location,
1986        )
1987    }
1988
1989    pub fn create_member_reference(member: AstNode, base: Option<AstNode>, id: AstId) -> AstNode {
1990        let location = base
1991            .as_ref()
1992            .map(|it| it.get_location().span(&member.get_location()))
1993            .unwrap_or_else(|| member.get_location());
1994        AstNode::new(
1995            AstStatement::ReferenceExpr(ReferenceExpr {
1996                access: ReferenceAccess::Member(Box::new(member)),
1997                base: base.map(Box::new),
1998            }),
1999            id,
2000            location,
2001        )
2002    }
2003
2004    pub fn create_global_reference(id: AstId, member: AstNode, location: SourceLocation) -> AstNode {
2005        AstNode {
2006            stmt: AstStatement::ReferenceExpr(ReferenceExpr {
2007                access: ReferenceAccess::Global(Box::new(member)),
2008                base: None,
2009            }),
2010            id,
2011            location,
2012            metadata: None,
2013        }
2014    }
2015
2016    pub fn create_index_reference(
2017        index: AstNode,
2018        base: Option<AstNode>,
2019        id: AstId,
2020        location: SourceLocation,
2021    ) -> AstNode {
2022        AstNode::new(
2023            AstStatement::ReferenceExpr(ReferenceExpr {
2024                access: ReferenceAccess::Index(Box::new(index)),
2025                base: base.map(Box::new),
2026            }),
2027            id,
2028            location,
2029        )
2030    }
2031
2032    pub fn create_address_of_reference(base: AstNode, id: AstId, location: SourceLocation) -> AstNode {
2033        AstNode::new(
2034            AstStatement::ReferenceExpr(ReferenceExpr {
2035                access: ReferenceAccess::Address,
2036                base: Some(Box::new(base)),
2037            }),
2038            id,
2039            location,
2040        )
2041    }
2042
2043    pub fn create_deref_reference(base: AstNode, id: AstId, location: SourceLocation) -> AstNode {
2044        AstNode::new(
2045            AstStatement::ReferenceExpr(ReferenceExpr {
2046                access: ReferenceAccess::Deref,
2047                base: Some(Box::new(base)),
2048            }),
2049            id,
2050            location,
2051        )
2052    }
2053
2054    pub fn create_direct_access(
2055        access: DirectAccessType,
2056        index: AstNode,
2057        id: AstId,
2058        location: SourceLocation,
2059    ) -> AstNode {
2060        AstNode::new(
2061            AstStatement::DirectAccess(DirectAccess { access, index: Box::new(index) }),
2062            id,
2063            location,
2064        )
2065    }
2066
2067    /// creates a new binary statement
2068    pub fn create_binary_expression(left: AstNode, operator: Operator, right: AstNode, id: AstId) -> AstNode {
2069        let location = left.location.span(&right.location);
2070        AstNode::new(
2071            AstStatement::BinaryExpression(BinaryExpression {
2072                left: Box::new(left),
2073                operator,
2074                right: Box::new(right),
2075            }),
2076            id,
2077            location,
2078        )
2079    }
2080
2081    /// creates a new cast statement
2082    pub fn create_cast_statement(
2083        type_name: AstNode,
2084        stmt: AstNode,
2085        location: &SourceLocation,
2086        id: AstId,
2087    ) -> AstNode {
2088        let new_location = location.span(&stmt.get_location());
2089        AstNode::new(
2090            AstStatement::ReferenceExpr(ReferenceExpr {
2091                access: ReferenceAccess::Cast(Box::new(stmt)),
2092                base: Some(Box::new(type_name)),
2093            }),
2094            id,
2095            new_location,
2096        )
2097    }
2098
2099    pub fn create_call_statement<T>(
2100        operator: AstNode,
2101        parameters: Option<AstNode>,
2102        id: usize,
2103        location: T,
2104    ) -> AstNode
2105    where
2106        T: Into<SourceLocation>,
2107    {
2108        AstNode::new(
2109            AstStatement::CallStatement(CallStatement {
2110                operator: Box::new(operator),
2111                parameters: parameters.map(Box::new),
2112            }),
2113            id,
2114            location.into(),
2115        )
2116    }
2117
2118    /// creates a new call statement to the given function and parameters
2119    pub fn create_call_to(
2120        function_name: String,
2121        parameters: Vec<AstNode>,
2122        id: usize,
2123        parameter_list_id: usize,
2124        location: &SourceLocation,
2125    ) -> AstNode {
2126        AstNode::new(
2127            AstStatement::CallStatement(CallStatement {
2128                operator: Box::new(AstFactory::create_member_reference(
2129                    AstFactory::create_identifier(&function_name, location, id),
2130                    None,
2131                    id,
2132                )),
2133                parameters: Some(Box::new(AstNode::new(
2134                    AstStatement::ExpressionList(parameters),
2135                    parameter_list_id,
2136                    SourceLocation::internal(), //TODO: get real location
2137                ))),
2138            }),
2139            id,
2140            location,
2141        )
2142    }
2143
2144    pub fn create_multiplied_statement(
2145        multiplier: u32,
2146        element: AstNode,
2147        location: SourceLocation,
2148        id: AstId,
2149    ) -> AstNode {
2150        AstNode::new(
2151            AstStatement::MultipliedStatement(MultipliedStatement { multiplier, element: Box::new(element) }),
2152            id,
2153            location,
2154        )
2155    }
2156
2157    pub fn create_range_statement(start: AstNode, end: AstNode, id: AstId) -> AstNode {
2158        let location = start.location.span(&end.location);
2159        let data = RangeStatement { start: Box::new(start), end: Box::new(end) };
2160        AstNode::new(AstStatement::RangeStatement(data), id, location)
2161    }
2162
2163    pub fn create_call_to_with_ids(
2164        function_name: &str,
2165        parameters: Vec<AstNode>,
2166        location: &SourceLocation,
2167        mut id_provider: IdProvider,
2168    ) -> AstNode {
2169        AstNode::new(
2170            AstStatement::CallStatement(CallStatement {
2171                operator: Box::new(AstFactory::create_member_reference(
2172                    AstFactory::create_identifier(function_name, location, id_provider.next_id()),
2173                    None,
2174                    id_provider.next_id(),
2175                )),
2176                parameters: Some(Box::new(AstFactory::create_expression_list(
2177                    parameters,
2178                    SourceLocation::internal(),
2179                    id_provider.next_id(),
2180                ))),
2181            }),
2182            id_provider.next_id(),
2183            location,
2184        )
2185    }
2186
2187    pub fn create_call_to_check_function_ast(
2188        check_function_name: &str,
2189        parameter: AstNode,
2190        sub_range: Range<AstNode>,
2191        location: &SourceLocation,
2192        id_provider: IdProvider,
2193    ) -> AstNode {
2194        AstFactory::create_call_to_with_ids(
2195            check_function_name,
2196            vec![parameter, sub_range.start, sub_range.end],
2197            location,
2198            id_provider,
2199        )
2200    }
2201
2202    pub fn create_jump_statement(
2203        condition: Box<AstNode>,
2204        target: Box<AstNode>,
2205        location: SourceLocation,
2206        id: AstId,
2207    ) -> AstNode {
2208        AstNode::new(AstStatement::JumpStatement(JumpStatement { condition, target }), id, location)
2209    }
2210
2211    pub fn create_label_statement(name: String, location: SourceLocation, id: AstId) -> AstNode {
2212        AstNode::new(AstStatement::LabelStatement(LabelStatement { name }), id, location)
2213    }
2214
2215    pub fn create_plus_one_expression(value: AstNode, location: SourceLocation, id: AstId) -> AstNode {
2216        let one = AstFactory::create_literal(AstLiteral::Integer(1), location.clone(), id);
2217        AstFactory::create_binary_expression(value, Operator::Plus, one, id)
2218    }
2219}
2220#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2221pub struct EmptyStatement {}
2222
2223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2224pub struct DefaultValue {}
2225
2226#[derive(Debug, Clone, PartialEq)]
2227pub struct CastStatement {
2228    pub target: Box<AstNode>,
2229    pub type_name: String,
2230}
2231
2232#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2233#[serde(bound(deserialize = "'de: 'static"))]
2234pub struct MultipliedStatement {
2235    pub multiplier: u32,
2236    pub element: Box<AstNode>,
2237}
2238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2239#[serde(bound(deserialize = "'de: 'static"))]
2240pub struct ReferenceExpr {
2241    pub access: ReferenceAccess,
2242    pub base: Option<Box<AstNode>>,
2243}
2244
2245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2246#[serde(bound(deserialize = "'de: 'static"))]
2247pub struct DirectAccess {
2248    pub access: DirectAccessType,
2249    pub index: Box<AstNode>,
2250}
2251
2252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2253#[serde(bound(deserialize = "'de: 'static"))]
2254pub struct HardwareAccess {
2255    pub direction: HardwareAccessType,
2256    pub access: DirectAccessType,
2257    pub address: Vec<AstNode>,
2258}
2259
2260#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2261#[serde(bound(deserialize = "'de: 'static"))]
2262pub struct BinaryExpression {
2263    pub operator: Operator,
2264    pub left: Box<AstNode>,
2265    pub right: Box<AstNode>,
2266}
2267
2268#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2269#[serde(bound(deserialize = "'de: 'static"))]
2270pub struct UnaryExpression {
2271    pub operator: Operator,
2272    pub value: Box<AstNode>,
2273}
2274
2275#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2276#[serde(bound(deserialize = "'de: 'static"))]
2277pub struct RangeStatement {
2278    pub start: Box<AstNode>,
2279    pub end: Box<AstNode>,
2280}
2281
2282#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2283#[serde(bound(deserialize = "'de: 'static"))]
2284pub struct Assignment {
2285    pub left: Box<AstNode>,
2286    pub right: Box<AstNode>,
2287}
2288
2289#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2290#[serde(bound(deserialize = "'de: 'static"))]
2291pub struct CallStatement {
2292    pub operator: Box<AstNode>,
2293    pub parameters: Option<Box<AstNode>>,
2294}
2295
2296/// Represents a conditional jump from current location to a specified label
2297#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2298#[serde(bound(deserialize = "'de: 'static"))]
2299pub struct JumpStatement {
2300    /// The condition based on which the current statement will perform a jump
2301    pub condition: Box<AstNode>,
2302    /// The target location (Label) the statement will jump to
2303    pub target: Box<AstNode>,
2304}
2305
2306/// Represents a location in code that could be jumbed to
2307#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2308pub struct LabelStatement {
2309    pub name: String,
2310}
2311
2312#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2313pub struct Allocation {
2314    pub name: String,
2315    pub reference_type: String,
2316    /// `true` when the allocated value is dead once the enclosing (lowered) statement
2317    /// completes — codegen may then bracket it with `llvm.lifetime` markers and the
2318    /// aggregate-type lowering may hand the slot to a later statement. `false` pins the
2319    /// slot for the whole function: loop bookkeeping values cross iterations, and temps
2320    /// whose address escapes the statement (`ADR`/`REF` arguments, interface fat-pointer
2321    /// captures) must stay valid and unshared.
2322    pub statement_scoped: bool,
2323}
2324
2325type DerefMarker = ();
2326
2327/// Builds the synthetic global name (`__PI_…`, `__M_…`, `__G_…`) that the pre-processor
2328/// emits for hardware-bound variables. Single source of truth: every code path that needs
2329/// to refer to one of these synthetic globals must call this function so that DWARF symbols,
2330/// initializer rewrites, and external mappings stay in lockstep.
2331pub fn mangle_hw_name(direction: HardwareAccessType, address: &[i128]) -> String {
2332    let prefix = match direction {
2333        HardwareAccessType::Input | HardwareAccessType::Output => "PI",
2334        HardwareAccessType::Memory => "M",
2335        HardwareAccessType::Global => "G",
2336    };
2337    let joined = address.iter().map(ToString::to_string).collect::<Vec<_>>().join("_");
2338    format!("__{prefix}_{joined}")
2339}
2340
2341impl HardwareAccess {
2342    pub fn get_mangled_variable_name(&self) -> String {
2343        let address: Vec<i128> =
2344            self.address.iter().flat_map(|node| node.get_literal_integer_value()).collect();
2345        mangle_hw_name(self.direction, &address)
2346    }
2347
2348    pub fn is_template(&self) -> bool {
2349        matches!(self.access, DirectAccessType::Template)
2350    }
2351}