55//! to include initialization code, making sure that the resulting AST is ready for
66//! further compilation stages.
77//! Initialization logic is as follows:
8- //! - Every struct(and POU) has an optional implicit initializer for constant fields.
9- //! - The name for this initializer is `<StructName>_init`
10- //! - The field is always private to the module
11- //! - Every struct(and POU) has a constructor for fields with pointer assignments or non-constant values
8+ //! - Every struct(and POU) has a constructor for fields with constant or pointer initializers.
129//! - The name for this constructor is `<StructName>_ctor`
13- //! - The constructor is always public and implicitly uses the implicit initializer
14- //! - Variables of the struct are initialized using the implicit initializer if their value is
15- //! derived at compile time, otherwise the constructor is used.
10+ //! - The constructor is always public
11+ //! - Variables of the struct are initialized by calling the constructor
1612//! - Global variables are initialized in a global constructor function called `__global_ctor`
1713//! - This function is called per module inside the static initialization code
1814//! - The function is private to the module
2117//! - External POUs and struct constructors are marked as `extern` and have no body.
2218//! - External variables are not re-initialized in the global constructor, they are assumed to be
2319//! initialized externally.
24- //! - Bulit -in types and variables are not re-initialized in the global
20+ //! - Built -in types and variables are not re-initialized in the global
2521//! constructor.
2622
2723use plc:: index:: { FxIndexMap , Index } ;
28- use plc_ast:: { ast:: AstNode , visitor:: AstVisitor } ;
24+ use plc_ast:: { ast:: AstNode , mut_visitor :: AstVisitorMut , visitor:: AstVisitor } ;
2925
3026#[ derive( Debug , PartialEq ) ]
3127enum Body {
@@ -36,29 +32,50 @@ enum Body {
3632
3733pub struct Initializer < ' idx > {
3834 index : & ' idx Index ,
39- implicit_initializers : FxIndexMap < String , Body > ,
35+ /// Stateful constructor per POU/struct
4036 constructors : FxIndexMap < String , Body > ,
37+ /// Constructors for temp and stack variables per POU
38+ stack_constructor : FxIndexMap < String , Vec < AstNode > > ,
39+ /// Global constructor statements
4140 global_constructor : Vec < AstNode > ,
4241}
4342
4443//TODO: might need to be a mutable ast visitor
45- impl AstVisitor for Initializer < ' _ > {
46- fn visit_compilation_unit ( & mut self , unit : & plc_ast:: ast:: CompilationUnit ) {
47- // Read all structs and POU structs, collect their implicit initializers if available
48- // Add a call to the constructor to memcpy the imlicit initializer
44+ impl AstVisitorMut for Initializer < ' _ > {
45+ fn visit_pou ( & mut self , pou : & mut plc_ast:: ast:: Pou ) {
46+ let constructor = match pou. linkage {
47+ plc_ast:: ast:: LinkageType :: Internal => vec ! [ ] ,
48+ plc_ast:: ast:: LinkageType :: External => {
49+ self . constructors . insert ( pou. name . clone ( ) , Body :: External ) ;
50+ return ;
51+ }
52+ plc_ast:: ast:: LinkageType :: BuiltIn => {
53+ self . constructors . insert ( pou. name . clone ( ) , Body :: None ) ;
54+ return ;
55+ }
56+ } ;
57+
58+ // Collect variable initializers
59+ for var in pou. variable_blocks . iter_mut ( ) { }
60+
61+ self . constructors . insert ( pou. name . clone ( ) , Body :: Internal ( constructor) ) ;
62+ }
63+
64+ fn visit_user_type_declaration ( & mut self , user_type : & mut plc_ast:: ast:: UserTypeDeclaration ) { }
65+
66+ fn visit_variable_block ( & mut self , var_block : & mut plc_ast:: ast:: VariableBlock ) { }
67+
68+ fn visit_compilation_unit ( & mut self , unit : & mut plc_ast:: ast:: CompilationUnit ) {
69+ // Read all structs and POU structs
70+ // Add a call to the constructor to initialize every variable
4971 // For each of the call statement or reference in the pou initializer, add an assignment to
5072 // the constructor
5173 }
5274}
5375
5476impl Initializer < ' _ > {
5577 pub fn new ( index : & Index ) -> Initializer < ' _ > {
56- Initializer {
57- index,
58- implicit_initializers : FxIndexMap :: default ( ) ,
59- constructors : FxIndexMap :: default ( ) ,
60- global_constructor : Vec :: new ( ) ,
61- }
78+ Initializer { index, constructors : FxIndexMap :: default ( ) , global_constructor : Vec :: new ( ) }
6279 }
6380}
6481
@@ -86,13 +103,8 @@ mod tests {
86103 for unit in & project. units {
87104 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
88105 }
89- // Check for implicit initializer
90- // Expecting a variable declaration: MyStruct MyStruct_init = {5, 3.14, TRUE};
91- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "MyStruct" ) , @r#""# ) ;
92- // Check for an empty constructor
93106 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
94- // Expecting a call to memcpy inside the constructor: memcpy(self, &MyStruct_init,
95- // sizeof(MyStruct));
107+ // Expecting assignments inside the constructor: self->a = 5; self->b = 3.14; self->c = 1;
96108 insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
97109 }
98110
@@ -120,20 +132,13 @@ mod tests {
120132 for unit in & project. units {
121133 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
122134 }
123- // Check for implicit initializers
124- // Expecting a variable declaration: InnerStruct InnerStruct_init = {10, 20};
125- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "InnerStruct" ) , @r#""# ) ;
126- // Expecting a variable declaration: OuterStruct OuterStruct_init = {0, 0, 2.71};
127- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "OuterStruct" ) , @r#""# ) ;
128135 // Check for constructors
129136 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
130- // Expecting a call to memcpy inside the constructor: memcpy(self, &InnerStruct_init,
131- // sizeof(InnerStruct));
137+ // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
132138 insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
133139 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
134- // Expecting a call to memcpy inside the constructor: memcpy(self, &OuterStruct_init,
135- // sizeof(OuterStruct));
136140 // Expecting a call to InnerStruct_ctor(&self->inner);
141+ // Expecting an assignment: self->z = 2.71;
137142 insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
138143 }
139144
@@ -162,23 +167,16 @@ mod tests {
162167 for unit in & project. units {
163168 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
164169 }
165- // Check for implicit initializers
166- // Expecting a variable declaration: InnerStruct InnerStruct_init = {10, 20};
167- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "InnerStruct" ) , @r#""# ) ;
168- // Expecting a variable declaration: OuterStruct OuterStruct_init = {10, 20, 10, 20, 2.71};
169- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "OuterStruct" ) , @r#""# ) ;
170170 // Check for constructors
171171 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
172- // Expecting a call to memcpy inside the constructor: memcpy(self, &InnerStruct_init,
173- // sizeof(InnerStruct));
172+ // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
174173 insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
175174 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
176- // Expecting a call to memcpy inside the constructor: memcpy(self, &OuterStruct_init,
177- // sizeof(OuterStruct));
178175 // Expecting a call to InnerStruct_ctor(&self->inner);
179176 // Expecting a call to InnerStruct_ctor(&self->inner2);
180177 // Expecting assignments: self->inner.x = 1; self->inner.y = 2;
181178 // Expecting assignments: self->inner2.y = 3;
179+ // Expecting an assignment: self->z = 2.71;
182180 insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
183181 }
184182
@@ -206,13 +204,9 @@ mod tests {
206204 for unit in & project. units {
207205 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
208206 }
209- // Check for implicit initializers
210- // Expecting a variable declaration: MyStruct MyStruct_init = {5, 0, 1};
211- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "MyStruct" ) , @r#""# ) ;
212207 // Check for constructor
213208 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
214- // Expecting a call to memcpy inside the constructor: memcpy(self, &MyStruct_init,
215- // sizeof(MyStruct));
209+ // Expecting assignments inside the constructor: self->a = 5; self->c = 1;
216210 // Expecting an assignment: self->b = &gVar;
217211 insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
218212 }
@@ -237,41 +231,39 @@ mod tests {
237231 for unit in & project. units {
238232 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
239233 }
240- // Check for implicit initializer
241- // Expecting a variable declaration: MyEnum MyEnum_init = 2;
242- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "MyEnum" ) , @r#""# ) ;
243234 // Expecting a function declaration: void MyEnum_ctor(MyEnum* self)
244- // Expecting an assignment inside the constructor: *self = MyEnum_init ;
235+ // Expecting an assignment inside the constructor: *self = 2 ;
245236 insta:: assert_debug_snapshot!( initializer. constructors. get( "MyEnum" ) , @r#""# ) ;
246- // Expecting a variable declaration: MyStruct MyStruct_init = {3, 42};
247- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "MyStruct" ) , @r#""# ) ;
248237 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
249- // Expecting a call to memcpy inside the constructor: memcpy(self, &MyStruct_init,
250- // sizeof(MyStruct));
251238 // Expecting a call to MyEnum_ctor(&self->e);
252239 // Expecting an assignment: self->e = 1;
240+ // Expecting an assignment: self->n = 42;
253241 insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
254242 }
255243
256244 #[ test]
257245 fn nested_struct_with_different_default_values ( ) {
258246 let src = r#"
247+ VAR_GLOBAL
248+ gVar : INT := 10;
249+ END_VAR
250+
259251 TYPE InnerStruct : STRUCT
260252 a : INT := 1;
261- b : POINTER TO INT := ADR(a );
253+ b : POINTER TO INT := ADR(gVar );
262254 END_STRUCT
263255
264256 TYPE InnerStruct2 : STRUCT
265257 c : INT := 4;
266258 d : INT := 5;
267259 inner : InnerStruct := (a := 6);
268- inner2 : InnerStruct := (b := ADR(c ));
260+ inner2 : InnerStruct := (b := ADR(gVar ));
269261 END_STRUCT
270262
271263 TYPE OuterStruct : STRUCT
272264 e : INT := 0;
273265 inner : InnerStruct2 := (a := 1, b := 2, inner := (a := 3));
274- inner2 : InnerStruct2 := (d := 8, inner := (b := ADR(e )));
266+ inner2 : InnerStruct2 := (d := 8, inner := (b := ADR(gVar )));
275267 inner3 : InnerStruct2 := (inner (a := 9));
276268 END_STRUCT
277269 "# ;
@@ -286,35 +278,23 @@ mod tests {
286278 for unit in & project. units {
287279 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
288280 }
289- // Check for implicit initializers
290- // Expecting a variable declaration: InnerStruct InnerStruct_init = {1, 0};
291- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "InnerStruct" ) , @r#""# ) ;
292- // Expecting a variable declaration: InnerStruct InnerStruct_init = {4, 5, 1, 0, 1, 0};
293- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "InnerStruct2" ) , @r#""# ) ;
294- // Expecting a variable declaration: OuterStruct OuterStruct_init = {0, 4, 5, 1, 0, 1, 0,
295- // 4, 5, 1, 0, 1, 0, 4, 5, 1, 0, 1, 0};
296- insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "OuterStruct" ) , @r#""# ) ;
297281 // Check for constructors
298282 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
299- // Expecting a call to memcpy inside the constructor: memcpy(self, &InnerStruct_init,
300- // sizeof(InnerStruct));
301- // Expecting an assignment: self->b = &self->a;
283+ // Expecting assignments inside the constructor: self->a = 1; self->b = &gVar;
302284 insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
303285 // Expecting a function declaration: void InnerStruct2_ctor(InnerStruct2* self)
304- // Expecting a call to memcpy inside the constructor: memcpy(self, &InnerStruct_init,
305- // sizeof(InnerStruct));
306286 // Expecting a call to InnerStruct_ctor(&self->inner);
307287 // Expecting a call to InnerStruct_ctor(&self->inner2);
308- // Expecting assignments: self->inner.a = 6; self->inner2.b = &self->c;
288+ // Expecting assignments: self->c = 4; self->d = 5;
289+ // Expecting assignments: self->inner.a = 6; self->inner2.b = &gvar;
309290 insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct2" ) , @r#""# ) ;
310291 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
311- // Expecting a call to memcpy inside the constructor: memcpy(self, &OuterStruct_init,
312- // sizeof(OuterStruct));
313292 // Expecting a call to InnerStruct2_ctor(&self->inner);
314293 // Expecting a call to InnerStruct2_ctor(&self->inner2);
315294 // Expecting a call to InnerStruct2_ctor(&self->inner3);
295+ // Expecting an assignment: self->e = 0;
316296 // Expecting assignments: self->inner.a = 1; self->inner.b = 2; self->inner.inner.a = 3;
317- // Expecting assignments: self->inner2.d = 8; self->inner2.inner.b = &self->e ;
297+ // Expecting assignments: self->inner2.d = 8; self->inner2.inner.b = &gVar ;
318298 // Expecting assignments: self->inner3.inner.a = 9;
319299 insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
320300 }
@@ -437,8 +417,7 @@ mod tests {
437417 // Expecting a call to MyExtStruct_ctor(&internalVar);
438418 // No call to MyExtStruct_ctor(&extVar);
439419 insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
440- // Check that no implicit initializer or constructor is generated for MyExtStruct
441- assert_eq ! ( initializer. implicit_initializers. get( "MyExtStruct" ) , None ) ;
420+ // Check that no constructor is generated for MyExtStruct
442421 insta:: assert_debug_snapshot!( initializer. constructors. get( "MyExtStruct" ) , @r#""# ) ;
443422 }
444423}
0 commit comments