@@ -40,9 +40,9 @@ enum Body {
4040 None ,
4141}
4242
43- pub struct Initializer < ' idx > {
43+ pub struct Initializer {
4444 id_provider : IdProvider ,
45- index : & ' idx Index ,
45+ index : Index ,
4646 /// Stateful constructor per POU/struct
4747 constructors : FxIndexMap < String , Body > ,
4848 /// Constructors for temp and stack variables per POU
@@ -52,7 +52,7 @@ pub struct Initializer<'idx> {
5252}
5353
5454//TODO: might need to be a mutable ast visitor
55- impl AstVisitor for Initializer < ' _ > {
55+ impl AstVisitor for Initializer {
5656 fn visit_pou ( & mut self , pou : & plc_ast:: ast:: Pou ) {
5757 match pou. linkage {
5858 plc_ast:: ast:: LinkageType :: External => {
@@ -93,13 +93,25 @@ impl AstVisitor for Initializer<'_> {
9393 self . stack_constructor . insert ( pou. name . clone ( ) , Body :: Internal ( stack_constructor) ) ;
9494 }
9595
96- fn visit_user_type_declaration ( & mut self , user_type : & plc_ast:: ast:: UserTypeDeclaration ) { }
96+ fn visit_user_type_declaration ( & mut self , user_type : & plc_ast:: ast:: UserTypeDeclaration ) {
97+ match user_type. linkage {
98+ plc_ast:: ast:: LinkageType :: External => {
99+ self . constructors . insert ( user_type. name . clone ( ) , Body :: External ) ;
100+ return ;
101+ }
102+ plc_ast:: ast:: LinkageType :: BuiltIn => {
103+ self . constructors . insert ( user_type. name . clone ( ) , Body :: None ) ;
104+ return ;
105+ }
106+ _ => { }
107+ } ;
97108
98- fn visit_variable_block ( & mut self , var_block : & plc_ast:: ast:: VariableBlock ) { }
109+ let mut constructor = vec ! [ ] ;
110+ }
99111}
100112
101- impl Initializer < ' _ > {
102- pub fn new ( id_provider : IdProvider , index : & Index ) -> Initializer < ' _ > {
113+ impl Initializer {
114+ pub fn new ( id_provider : IdProvider , index : Index ) -> Initializer {
103115 Initializer {
104116 id_provider,
105117 index,
@@ -110,9 +122,14 @@ impl Initializer<'_> {
110122 }
111123}
112124
125+ #[ cfg( test) ]
113126mod tests {
114127 use plc_ast:: { ast:: AstNode , visitor:: AstVisitor } ;
115128 use plc_diagnostics:: diagnostician:: Diagnostician ;
129+ use plc_driver:: pipelines:: BuildPipeline ;
130+ use plc_source:: SourceCode ;
131+
132+ use crate :: initializer:: Initializer ;
116133
117134 fn print_to_string ( nodes : & [ AstNode ] ) -> String {
118135 nodes. iter ( ) . map ( |it| it. as_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "\n " )
@@ -126,6 +143,20 @@ mod tests {
126143 }
127144 }
128145
146+ fn parse_and_init ( src : & str ) -> Initializer {
147+ let src: SourceCode = src. into ( ) ;
148+ let diagnostician = Diagnostician :: buffered ( ) ;
149+ let mut pipeline = BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician) . unwrap ( ) ;
150+ let mut project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
151+ // Visit the AST with the Initializer
152+ let mut initializer =
153+ super :: Initializer :: new ( pipeline. context . provider ( ) , std:: mem:: take ( & mut project. index ) ) ;
154+ for unit in & project. units {
155+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
156+ }
157+ initializer
158+ }
159+
129160 #[ test]
130161 fn struct_gets_imlicit_initializer_and_constructor ( ) {
131162 let src = r#"
@@ -134,18 +165,10 @@ mod tests {
134165 b : REAL := 3.14;
135166 c : BOOL := TRUE;
136167 END_STRUCT
168+ END_TYPE
137169 "# ;
138170
139- let diagnostician = Diagnostician :: buffered ( ) ;
140- let mut pipeline =
141- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
142- . unwrap ( ) ;
143- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
144- // Visit the AST with the Initializer
145- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
146- for unit in & project. units {
147- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
148- }
171+ let initializer = parse_and_init ( src) ;
149172 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
150173 // Expecting assignments inside the constructor: self->a = 5; self->b = 3.14; self->c = 1;
151174 insta:: assert_debug_snapshot!( print_body_to_string( initializer. constructors. get( "MyStruct" ) . unwrap( ) ) , @r#""# ) ;
@@ -158,23 +181,16 @@ mod tests {
158181 x : INT := 10;
159182 y : INT := 20;
160183 END_STRUCT
184+ END_TYPE
161185
162186 TYPE OuterStruct : STRUCT
163187 inner : InnerStruct;
164188 z : REAL := 2.71;
165189 END_STRUCT
190+ END_TYPE
166191 "# ;
167192
168- let diagnostician = Diagnostician :: buffered ( ) ;
169- let mut pipeline =
170- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
171- . unwrap ( ) ;
172- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
173- // Visit the AST with the Initializer
174- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
175- for unit in & project. units {
176- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
177- }
193+ let initializer = parse_and_init ( src) ;
178194 // Check for constructors
179195 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
180196 // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
@@ -192,24 +208,17 @@ mod tests {
192208 x : INT := 10;
193209 y : INT := 20;
194210 END_STRUCT
211+ END_TYPE
195212
196213 TYPE OuterStruct : STRUCT
197214 inner : InnerStruct := (x := 1, y := 2);
198215 inner2 : InnerStruct := (y := 3);
199216 z : REAL := 2.71;
200217 END_STRUCT
218+ END_TYPE
201219 "# ;
202220
203- let diagnostician = Diagnostician :: buffered ( ) ;
204- let mut pipeline =
205- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
206- . unwrap ( ) ;
207- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
208- // Visit the AST with the Initializer
209- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
210- for unit in & project. units {
211- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
212- }
221+ let initializer = parse_and_init ( src) ;
213222 // Check for constructors
214223 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
215224 // Expecting assignments inside the constructor: self->x = 10; self->y = 20;
@@ -235,18 +244,10 @@ mod tests {
235244 b : POINTER TO INT := ADR(gVar);
236245 c : BOOL := TRUE;
237246 END_STRUCT
247+ END_TYPE
238248 "# ;
239249
240- let diagnostician = Diagnostician :: buffered ( ) ;
241- let mut pipeline =
242- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
243- . unwrap ( ) ;
244- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
245- // Visit the AST with the Initializer
246- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
247- for unit in & project. units {
248- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
249- }
250+ let initializer = parse_and_init ( src) ;
250251 // Check for constructor
251252 // Expecting a function declaration: void MyStruct_ctor(MyStruct* self)
252253 // Expecting assignments inside the constructor: self->a = 5; self->c = 1;
@@ -257,23 +258,15 @@ mod tests {
257258 #[ test]
258259 fn enum_default_values_in_struct ( ) {
259260 let src = r#"
260- TYPE MyEnum : (Option1, Option2, Option3) := Option3;
261+ TYPE MyEnum : (Option1, Option2, Option3) := Option3; END_TYPE
261262 TYPE MyStruct : STRUCT
262263 e : MyEnum := Option2;
263264 n : INT := 42;
264265 END_STRUCT
266+ END_TYPE
265267 "# ;
266268
267- let diagnostician = Diagnostician :: buffered ( ) ;
268- let mut pipeline =
269- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
270- . unwrap ( ) ;
271- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
272- // Visit the AST with the Initializer
273- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
274- for unit in & project. units {
275- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
276- }
269+ let initializer = parse_and_init ( src) ;
277270 // Expecting a function declaration: void MyEnum_ctor(MyEnum* self)
278271 // Expecting an assignment inside the constructor: *self = 2;
279272 insta:: assert_debug_snapshot!( print_body_to_string( initializer. constructors. get( "MyEnum" ) . unwrap( ) ) , @r#""# ) ;
@@ -295,32 +288,26 @@ mod tests {
295288 a : INT := 1;
296289 b : POINTER TO INT := ADR(gVar);
297290 END_STRUCT
291+ END_TYPE
298292
299293 TYPE InnerStruct2 : STRUCT
300294 c : INT := 4;
301295 d : INT := 5;
302296 inner : InnerStruct := (a := 6);
303297 inner2 : InnerStruct := (b := ADR(gVar));
304298 END_STRUCT
299+ END_TYPE
305300
306301 TYPE OuterStruct : STRUCT
307302 e : INT := 0;
308303 inner : InnerStruct2 := (a := 1, b := 2, inner := (a := 3));
309304 inner2 : InnerStruct2 := (d := 8, inner := (b := ADR(gVar)));
310305 inner3 : InnerStruct2 := (inner (a := 9));
311306 END_STRUCT
307+ END_TYPE
312308 "# ;
313309
314- let diagnostician = Diagnostician :: buffered ( ) ;
315- let mut pipeline =
316- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
317- . unwrap ( ) ;
318- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
319- // Visit the AST with the Initializer
320- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
321- for unit in & project. units {
322- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
323- }
310+ let initializer = parse_and_init ( src) ;
324311 // Check for constructors
325312 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
326313 // Expecting assignments inside the constructor: self->a = 1; self->b = &gVar;
@@ -356,18 +343,10 @@ mod tests {
356343 b : POINTER TO INT := ADR(gVar1);
357344 c : BOOL := TRUE;
358345 END_STRUCT
346+ END_TYPE
359347 "# ;
360348
361- let diagnostician = Diagnostician :: buffered ( ) ;
362- let mut pipeline =
363- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
364- . unwrap ( ) ;
365- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
366- // Visit the AST with the Initializer
367- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
368- for unit in & project. units {
369- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
370- }
349+ let initializer = parse_and_init ( src) ;
371350 // Check for global constructor
372351 // Expecting a call to MyStruct_ctor(&gStructVar);
373352 insta:: assert_debug_snapshot!( print_to_string( & initializer. global_constructor) , @r#""# ) ;
@@ -386,18 +365,10 @@ mod tests {
386365 a : INT := 5;
387366 b : BOOL := TRUE;
388367 END_STRUCT
368+ END_TYPE
389369 "# ;
390370
391- let diagnostician = Diagnostician :: buffered ( ) ;
392- let mut pipeline =
393- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
394- . unwrap ( ) ;
395- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
396- // Visit the AST with the Initializer
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- }
371+ let initializer = parse_and_init ( src) ;
401372 // Check for function constructor on the stack
402373 // Expecting a call to MyStruct_ctor(&localStruct);
403374 insta:: assert_debug_snapshot!( print_body_to_string( initializer. stack_constructor. get( "MyFunction" ) . unwrap( ) ) , @r#""# ) ;
@@ -413,23 +384,16 @@ mod tests {
413384 VAR
414385 localStruct : MyStruct;
415386 END_VAR
387+ END_PROGRAM
416388
417389 TYPE MyStruct : STRUCT
418390 a : INT := 5;
419391 b : BOOL := TRUE;
420392 END_STRUCT
393+ END_TYPE
421394 "# ;
422395
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 ) ;
430- for unit in & project. units {
431- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
432- }
396+ let initializer = parse_and_init ( src) ;
433397 // Check for program constructor on the stack
434398 // Expecting a call to MyStruct_ctor(&localStruct);
435399 insta:: assert_debug_snapshot!( print_body_to_string( initializer. stack_constructor. get( "MyProgram" ) . unwrap( ) ) , @r#""# ) ;
@@ -446,16 +410,7 @@ mod tests {
446410 END_PROGRAM
447411 "# ;
448412
449- let diagnostician = Diagnostician :: buffered ( ) ;
450- let mut pipeline =
451- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
452- . unwrap ( ) ;
453- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
454- // Visit the AST with the Initializer
455- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
456- for unit in & project. units {
457- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
458- }
413+ let initializer = parse_and_init ( src) ;
459414 // Check for program constructor
460415 // Expecting a call to MyProgram_ctor(&progStruct);
461416 insta:: assert_debug_snapshot!( print_to_string( & initializer. global_constructor) , @r#""# ) ;
@@ -478,18 +433,10 @@ mod tests {
478433 a : INT := 5;
479434 b : BOOL := TRUE;
480435 END_STRUCT
436+ END_TYPE
481437 "# ;
482438
483- let diagnostician = Diagnostician :: buffered ( ) ;
484- let mut pipeline =
485- plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
486- . unwrap ( ) ;
487- let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
488- // Visit the AST with the Initializer
489- let mut initializer = super :: Initializer :: new ( pipeline. context . provider ( ) , & project. index ) ;
490- for unit in & project. units {
491- initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
492- }
439+ let initializer = parse_and_init ( src) ;
493440 // Check for internal var assignment in global constructor
494441 // Expecting a call to MyExtStruct_ctor(&internalVar);
495442 // No call to MyExtStruct_ctor(&extVar);
0 commit comments