2020//! - Built-in types and variables are not re-initialized in the global
2121//! constructor.
2222
23- use plc:: index:: { FxIndexMap , Index } ;
24- use plc_ast:: { ast:: AstNode , mut_visitor:: AstVisitorMut , visitor:: AstVisitor } ;
23+ use std:: any:: Any ;
24+
25+ use plc:: {
26+ index:: { FxIndexMap , Index } ,
27+ lowering:: helper:: create_assignment,
28+ } ;
29+ use plc_ast:: {
30+ ast:: { AstFactory , AstNode , CompilationUnit } ,
31+ mut_visitor:: AstVisitorMut ,
32+ provider:: IdProvider ,
33+ visitor:: AstVisitor ,
34+ } ;
2535
2636#[ derive( Debug , PartialEq ) ]
2737enum Body {
@@ -31,20 +41,20 @@ enum Body {
3141}
3242
3343pub struct Initializer < ' idx > {
44+ id_provider : IdProvider ,
3445 index : & ' idx Index ,
3546 /// Stateful constructor per POU/struct
3647 constructors : FxIndexMap < String , Body > ,
3748 /// Constructors for temp and stack variables per POU
38- stack_constructor : FxIndexMap < String , Vec < AstNode > > ,
49+ stack_constructor : FxIndexMap < String , Body > ,
3950 /// Global constructor statements
4051 global_constructor : Vec < AstNode > ,
4152}
4253
4354//TODO: might need to be a mutable ast visitor
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 ! [ ] ,
55+ impl AstVisitor for Initializer < ' _ > {
56+ fn visit_pou ( & mut self , pou : & plc_ast:: ast:: Pou ) {
57+ match pou. linkage {
4858 plc_ast:: ast:: LinkageType :: External => {
4959 self . constructors . insert ( pou. name . clone ( ) , Body :: External ) ;
5060 return ;
@@ -53,36 +63,69 @@ impl AstVisitorMut for Initializer<'_> {
5363 self . constructors . insert ( pou. name . clone ( ) , Body :: None ) ;
5464 return ;
5565 }
66+ _ => { }
5667 } ;
5768
69+ let mut constructor = vec ! [ ] ;
70+ let mut stack_constructor = vec ! [ ] ;
71+
5872 // Collect variable initializers
59- for var in pou. variable_blocks . iter_mut ( ) { }
73+ for var in pou. variable_blocks . iter ( ) {
74+ for variable in var. variables . iter ( ) {
75+ if let Some ( initializer) = & variable. initializer {
76+ // Create an assignment "self.<variable.name> := <initializer>"
77+ let assignment = create_assignment (
78+ variable. get_name ( ) ,
79+ Some ( "self" ) ,
80+ initializer,
81+ self . id_provider . clone ( ) ,
82+ ) ;
83+ if var. is_temp ( ) || ( var. is_local ( ) && !pou. is_stateful ( ) ) {
84+ stack_constructor. push ( assignment) ;
85+ } else {
86+ constructor. push ( assignment) ;
87+ }
88+ }
89+ }
90+ }
6091
6192 self . constructors . insert ( pou. name . clone ( ) , Body :: Internal ( constructor) ) ;
93+ self . stack_constructor . insert ( pou. name . clone ( ) , Body :: Internal ( stack_constructor) ) ;
6294 }
6395
64- fn visit_user_type_declaration ( & mut self , user_type : & mut plc_ast:: ast:: UserTypeDeclaration ) { }
96+ fn visit_user_type_declaration ( & mut self , user_type : & plc_ast:: ast:: UserTypeDeclaration ) { }
6597
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
71- // For each of the call statement or reference in the pou initializer, add an assignment to
72- // the constructor
73- }
98+ fn visit_variable_block ( & mut self , var_block : & plc_ast:: ast:: VariableBlock ) { }
7499}
75100
76101impl Initializer < ' _ > {
77- pub fn new ( index : & Index ) -> Initializer < ' _ > {
78- Initializer { index, constructors : FxIndexMap :: default ( ) , global_constructor : Vec :: new ( ) }
102+ pub fn new ( id_provider : IdProvider , index : & Index ) -> Initializer < ' _ > {
103+ Initializer {
104+ id_provider,
105+ index,
106+ constructors : FxIndexMap :: default ( ) ,
107+ stack_constructor : FxIndexMap :: default ( ) ,
108+ global_constructor : Vec :: new ( ) ,
109+ }
79110 }
80111}
81112
82113mod tests {
83- use plc_ast:: visitor:: AstVisitor ;
114+ use plc_ast:: { ast :: AstNode , visitor:: AstVisitor } ;
84115 use plc_diagnostics:: diagnostician:: Diagnostician ;
85116
117+ fn print_to_string ( nodes : & [ AstNode ] ) -> String {
118+ nodes. iter ( ) . map ( |it| it. as_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "\n " )
119+ }
120+
121+ fn print_body_to_string ( body : & super :: Body ) -> String {
122+ match body {
123+ super :: Body :: Internal ( nodes) => print_to_string ( nodes) ,
124+ super :: Body :: External => "extern" . to_string ( ) ,
125+ super :: Body :: None => "none" . to_string ( ) ,
126+ }
127+ }
128+
86129 #[ test]
87130 fn struct_gets_imlicit_initializer_and_constructor ( ) {
88131 let src = r#"
@@ -99,13 +142,13 @@ mod tests {
99142 . unwrap ( ) ;
100143 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
101144 // Visit the AST with the Initializer
102- let mut initializer = super :: Initializer :: new ( & project. index ) ;
145+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
103146 for unit in & project. units {
104147 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
105148 }
106149 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
107150 // Expecting assignments inside the constructor: self->a = 5; self->b = 3.14; self->c = 1;
108- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
151+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "MyStruct" ) . unwrap ( ) ) , @r#""# ) ;
109152 }
110153
111154 #[ test]
@@ -128,18 +171,18 @@ mod tests {
128171 . unwrap ( ) ;
129172 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
130173 // Visit the AST with the Initializer
131- let mut initializer = super :: Initializer :: new ( & project. index ) ;
174+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
132175 for unit in & project. units {
133176 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
134177 }
135178 // Check for constructors
136179 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
137180 // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
138- insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
181+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "InnerStruct" ) . unwrap ( ) ) , @r#""# ) ;
139182 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
140183 // Expecting a call to InnerStruct_ctor(&self->inner);
141184 // Expecting an assignment: self->z = 2.71;
142- insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
185+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "OuterStruct" ) . unwrap ( ) ) , @r#""# ) ;
143186 }
144187
145188 #[ test]
@@ -163,21 +206,21 @@ mod tests {
163206 . unwrap ( ) ;
164207 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
165208 // Visit the AST with the Initializer
166- let mut initializer = super :: Initializer :: new ( & project. index ) ;
209+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
167210 for unit in & project. units {
168211 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
169212 }
170213 // Check for constructors
171214 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
172215 // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
173- insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
216+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "InnerStruct" ) . unwrap ( ) ) , @r#""# ) ;
174217 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
175218 // Expecting a call to InnerStruct_ctor(&self->inner);
176219 // Expecting a call to InnerStruct_ctor(&self->inner2);
177220 // Expecting assignments: self->inner.x = 1; self->inner.y = 2;
178221 // Expecting assignments: self->inner2.y = 3;
179222 // Expecting an assignment: self->z = 2.71;
180- insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
223+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "OuterStruct" ) . unwrap ( ) ) , @r#""# ) ;
181224 }
182225
183226 #[ test]
@@ -200,15 +243,15 @@ mod tests {
200243 . unwrap ( ) ;
201244 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
202245 // Visit the AST with the Initializer
203- let mut initializer = super :: Initializer :: new ( & project. index ) ;
246+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
204247 for unit in & project. units {
205248 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
206249 }
207250 // Check for constructor
208251 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
209252 // Expecting assignments inside the constructor: self->a = 5; self->c = 1;
210253 // Expecting an assignment: self->b = &gVar;
211- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
254+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "MyStruct" ) . unwrap ( ) ) , @r#""# ) ;
212255 }
213256
214257 #[ test]
@@ -227,18 +270,18 @@ mod tests {
227270 . unwrap ( ) ;
228271 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
229272 // Visit the AST with the Initializer
230- let mut initializer = super :: Initializer :: new ( & project. index ) ;
273+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
231274 for unit in & project. units {
232275 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
233276 }
234277 // Expecting a function declaration: void MyEnum_ctor(MyEnum* self)
235278 // Expecting an assignment inside the constructor: *self = 2;
236- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyEnum" ) , @r#""# ) ;
279+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "MyEnum" ) . unwrap ( ) ) , @r#""# ) ;
237280 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
238281 // Expecting a call to MyEnum_ctor(&self->e);
239282 // Expecting an assignment: self->e = 1;
240283 // Expecting an assignment: self->n = 42;
241- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
284+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "MyStruct" ) . unwrap ( ) ) , @r#""# ) ;
242285 }
243286
244287 #[ test]
@@ -274,20 +317,20 @@ mod tests {
274317 . unwrap ( ) ;
275318 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
276319 // Visit the AST with the Initializer
277- let mut initializer = super :: Initializer :: new ( & project. index ) ;
320+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
278321 for unit in & project. units {
279322 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
280323 }
281324 // Check for constructors
282325 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
283326 // Expecting assignments inside the constructor: self->a = 1; self->b = &gVar;
284- insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
327+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "InnerStruct" ) . unwrap ( ) ) , @r#""# ) ;
285328 // Expecting a function declaration: void InnerStruct2_ctor(InnerStruct2* self)
286329 // Expecting a call to InnerStruct_ctor(&self->inner);
287330 // Expecting a call to InnerStruct_ctor(&self->inner2);
288331 // Expecting assignments: self->c = 4; self->d = 5;
289332 // Expecting assignments: self->inner.a = 6; self->inner2.b = &gvar;
290- insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct2" ) , @r#""# ) ;
333+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "InnerStruct2" ) . unwrap ( ) ) , @r#""# ) ;
291334 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
292335 // Expecting a call to InnerStruct2_ctor(&self->inner);
293336 // Expecting a call to InnerStruct2_ctor(&self->inner2);
@@ -296,7 +339,7 @@ mod tests {
296339 // Expecting assignments: self->inner.a = 1; self->inner.b = 2; self->inner.inner.a = 3;
297340 // Expecting assignments: self->inner2.d = 8; self->inner2.inner.b = &gVar;
298341 // Expecting assignments: self->inner3.inner.a = 9;
299- insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
342+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "OuterStruct" ) . unwrap ( ) ) , @r#""# ) ;
300343 }
301344
302345 #[ test]
@@ -321,13 +364,13 @@ mod tests {
321364 . unwrap ( ) ;
322365 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
323366 // Visit the AST with the Initializer
324- let mut initializer = super :: Initializer :: new ( & project. index ) ;
367+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
325368 for unit in & project. units {
326369 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
327370 }
328371 // Check for global constructor
329372 // Expecting a call to MyStruct_ctor(&gStructVar);
330- insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
373+ insta:: assert_debug_snapshot!( print_to_string ( & initializer. global_constructor) , @r#""# ) ;
331374 }
332375
333376 #[ test]
@@ -351,13 +394,47 @@ mod tests {
351394 . unwrap ( ) ;
352395 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
353396 // Visit the AST with the Initializer
354- let mut initializer = super :: Initializer :: new ( & project. index ) ;
397+ let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
398+ for unit in & project. units {
399+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
400+ }
401+ // Check for function constructor on the stack
402+ // Expecting a call to MyStruct_ctor(&localStruct);
403+ insta:: assert_debug_snapshot!( print_body_to_string( initializer. stack_constructor. get( "MyFunction" ) . unwrap( ) ) , @r#""# ) ;
404+ }
405+
406+ #[ test]
407+ fn program_temp_variables_are_in_stack_constructor ( ) {
408+ let src = r#"
409+ PROGRAM MyProgram
410+ VAR_TEMP
411+ tempStruct : MyStruct;
412+ END_VAR
413+ VAR
414+ localStruct : MyStruct;
415+ END_VAR
416+
417+ TYPE MyStruct : STRUCT
418+ a : INT := 5;
419+ b : BOOL := TRUE;
420+ END_STRUCT
421+ "# ;
422+
423+ let diagnostician = Diagnostician :: buffered ( ) ;
424+ let mut pipeline =
425+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
426+ . unwrap ( ) ;
427+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
428+ // Visit the AST with the Initializer
429+ let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
355430 for unit in & project. units {
356431 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
357432 }
358- // Check for function constructor
433+ // Check for program constructor on the stack
359434 // Expecting a call to MyStruct_ctor(&localStruct);
360- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyFunction" ) , @r#""# ) ;
435+ insta:: assert_debug_snapshot!( print_body_to_string( initializer. stack_constructor. get( "MyProgram" ) . unwrap( ) ) , @r#""# ) ;
436+ // Check for program constructor
437+ insta:: assert_debug_snapshot!( print_body_to_string( initializer. constructors. get( "MyProgram" ) . unwrap( ) ) , @r#""# ) ;
361438 }
362439
363440 #[ test]
@@ -375,13 +452,13 @@ mod tests {
375452 . unwrap ( ) ;
376453 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
377454 // Visit the AST with the Initializer
378- let mut initializer = super :: Initializer :: new ( & project. index ) ;
455+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
379456 for unit in & project. units {
380457 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
381458 }
382459 // Check for program constructor
383460 // Expecting a call to MyProgram_ctor(&progStruct);
384- insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
461+ insta:: assert_debug_snapshot!( print_to_string ( & initializer. global_constructor) , @r#""# ) ;
385462 }
386463
387464 #[ test]
@@ -409,15 +486,15 @@ mod tests {
409486 . unwrap ( ) ;
410487 let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
411488 // Visit the AST with the Initializer
412- let mut initializer = super :: Initializer :: new ( & project. index ) ;
489+ let mut initializer = super :: Initializer :: new ( pipeline . context . provider ( ) , & project. index ) ;
413490 for unit in & project. units {
414491 initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
415492 }
416493 // Check for internal var assignment in global constructor
417494 // Expecting a call to MyExtStruct_ctor(&internalVar);
418495 // No call to MyExtStruct_ctor(&extVar);
419- insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
496+ insta:: assert_debug_snapshot!( print_to_string ( & initializer. global_constructor) , @r#""# ) ;
420497 // Check that no constructor is generated for MyExtStruct
421- insta:: assert_debug_snapshot!( initializer. constructors. get( "MyExtStruct" ) , @r#""# ) ;
498+ insta:: assert_debug_snapshot!( print_body_to_string ( initializer. constructors. get( "MyExtStruct" ) . unwrap ( ) ) , @r#""# ) ;
422499 }
423500}
0 commit comments