1use 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 pub location: SourceLocation,
42 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 pub interfaces: Vec<Identifier>,
52
53 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#[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 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 Internal,
344 External,
346 Include,
351 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, 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 parent: String,
408
409 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 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 pub pous: Vec<Pou>,
487 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 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 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>, variables: Vec<Variable>,
833 },
834 EnumType {
835 name: Option<String>, numeric_type: String,
837 elements: AstNode, },
839 SubRangeType {
840 name: Option<String>,
841 referenced_type: String,
842 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 type_safe: bool,
862
863 is_function: bool,
865 },
866 StringType {
867 name: Option<String>,
868 is_wide: bool, size: Option<AstNode>,
870 },
871 VarArgs {
872 referenced_type: Option<Box<DataTypeDeclaration>>,
873 sized: bool, },
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 Default,
886
887 Alias,
889
890 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 { .. } => {} }
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 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 Global(Box<AstNode>),
969
970 Member(Box<AstNode>),
972
973 Index(Box<AstNode>),
975
976 Cast(Box<AstNode>),
978
979 Deref,
981
982 Address,
984}
985
986#[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 DefaultValue(DefaultValue),
1036
1037 Literal(AstLiteral),
1039 MultipliedStatement(MultipliedStatement),
1040
1041 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 Assignment(Assignment),
1061 OutputAssignment(Assignment),
1062 RefAssignment(Assignment),
1063
1064 CallStatement(CallStatement),
1065
1066 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]
1080macro_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]
1094macro_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 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 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 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 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 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 pub fn is_cast_prefix_eligible(&self) -> bool {
1323 match &self.stmt {
1325 AstStatement::Literal(kind, ..) => kind.is_cast_prefix_eligible(),
1326 AstStatement::Identifier(..) => true,
1327 _ => false,
1328 }
1329 }
1330
1331 pub fn is_flat_reference(&self) -> bool {
1333 self.get_flat_reference_name().is_some()
1334 }
1335
1336 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 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 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 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
1704pub 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
1714pub 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
1728pub 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 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 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 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 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 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 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 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 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 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 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 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 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 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(), ))),
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#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2298#[serde(bound(deserialize = "'de: 'static"))]
2299pub struct JumpStatement {
2300 pub condition: Box<AstNode>,
2302 pub target: Box<AstNode>,
2304}
2305
2306#[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 pub statement_scoped: bool,
2323}
2324
2325type DerefMarker = ();
2326
2327pub 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}