2727use plc:: index:: { FxIndexMap , Index } ;
2828use plc_ast:: { ast:: AstNode , visitor:: AstVisitor } ;
2929
30- #[ derive( Debug ) ]
30+ #[ derive( Debug , PartialEq ) ]
3131enum Body {
3232 Internal ( Vec < AstNode > ) ,
3333 External ,
@@ -147,6 +147,7 @@ mod tests {
147147
148148 TYPE OuterStruct : STRUCT
149149 inner : InnerStruct := (x := 1, y := 2);
150+ inner2 : InnerStruct := (y := 3);
150151 z : REAL := 2.71;
151152 END_STRUCT
152153 "# ;
@@ -164,7 +165,7 @@ mod tests {
164165 // Check for implicit initializers
165166 // Expecting a variable declaration: InnerStruct InnerStruct_init = {10, 20};
166167 insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "InnerStruct" ) , @r#""# ) ;
167- // Expecting a variable declaration: OuterStruct OuterStruct_init = {1, 2 , 2.71};
168+ // Expecting a variable declaration: OuterStruct OuterStruct_init = {10, 20, 10, 20 , 2.71};
168169 insta:: assert_debug_snapshot!( initializer. implicit_initializers. get( "OuterStruct" ) , @r#""# ) ;
169170 // Check for constructors
170171 // Expecting a function declaration: void InnerStruct_ctor(InnerStruct* self)
@@ -174,17 +175,270 @@ mod tests {
174175 // Expecting a function declaration: void OuterStruct_ctor(OuterStruct* self)
175176 // Expecting a call to memcpy inside the constructor: memcpy(self, &OuterStruct_init,
176177 // sizeof(OuterStruct));
177- // TODO: how do we prevent this from overriding the set values?
178178 // Expecting a call to InnerStruct_ctor(&self->inner);
179+ // Expecting a call to InnerStruct_ctor(&self->inner2);
180+ // Expecting assignments: self->inner.x = 1; self->inner.y = 2;
181+ // Expecting assignments: self->inner2.y = 3;
179182 insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
180183 }
181184
182185 #[ test]
183- fn variable_with_pointer_initializer_is_added_to_constructor ( ) { }
186+ fn variable_with_pointer_initializer_is_added_to_constructor ( ) {
187+ let src = r#"
188+ VAR_GLOBAL
189+ gVar : INT;
190+ myStructVar : MyStruct;
191+ END_VAR
192+ TYPE MyStruct : STRUCT
193+ a : INT := 5;
194+ b : POINTER TO INT := ADR(gVar);
195+ c : BOOL := TRUE;
196+ END_STRUCT
197+ "# ;
198+
199+ let diagnostician = Diagnostician :: buffered ( ) ;
200+ let mut pipeline =
201+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
202+ . unwrap ( ) ;
203+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
204+ // Visit the AST with the Initializer
205+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
206+ for unit in & project. units {
207+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
208+ }
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#""# ) ;
212+ // Check for constructor
213+ // 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));
216+ // Expecting an assignment: self->b = &gVar;
217+ insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
218+ }
184219
185220 #[ test]
186- fn enum_default_values_in_struct ( ) { }
221+ fn enum_default_values_in_struct ( ) {
222+ let src = r#"
223+ TYPE MyEnum : (Option1, Option2, Option3) := Option3;
224+ TYPE MyStruct : STRUCT
225+ e : MyEnum := Option2;
226+ n : INT := 42;
227+ END_STRUCT
228+ "# ;
229+
230+ let diagnostician = Diagnostician :: buffered ( ) ;
231+ let mut pipeline =
232+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
233+ . unwrap ( ) ;
234+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
235+ // Visit the AST with the Initializer
236+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
237+ for unit in & project. units {
238+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
239+ }
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#""# ) ;
243+ // Expecting a function declaration: void MyEnum_ctor(MyEnum* self)
244+ // Expecting an assignment inside the constructor: *self = MyEnum_init;
245+ 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#""# ) ;
248+ // 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));
251+ // Expecting a call to MyEnum_ctor(&self->e);
252+ // Expecting an assignment: self->e = 1;
253+ insta:: assert_debug_snapshot!( initializer. constructors. get( "MyStruct" ) , @r#""# ) ;
254+ }
187255
188256 #[ test]
189- fn nested_struct_with_different_default_values ( ) { }
257+ fn nested_struct_with_different_default_values ( ) {
258+ let src = r#"
259+ TYPE InnerStruct : STRUCT
260+ a : INT := 1;
261+ b : POINTER TO INT := ADR(a);
262+ END_STRUCT
263+
264+ TYPE InnerStruct2 : STRUCT
265+ c : INT := 4;
266+ d : INT := 5;
267+ inner : InnerStruct := (a := 6);
268+ inner2 : InnerStruct := (b := ADR(c));
269+ END_STRUCT
270+
271+ TYPE OuterStruct : STRUCT
272+ e : INT := 0;
273+ inner : InnerStruct2 := (a := 1, b := 2, inner := (a := 3));
274+ inner2 : InnerStruct2 := (d := 8, inner := (b := ADR(e)));
275+ inner3 : InnerStruct2 := (inner (a := 9));
276+ END_STRUCT
277+ "# ;
278+
279+ let diagnostician = Diagnostician :: buffered ( ) ;
280+ let mut pipeline =
281+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
282+ . unwrap ( ) ;
283+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
284+ // Visit the AST with the Initializer
285+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
286+ for unit in & project. units {
287+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
288+ }
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#""# ) ;
297+ // Check for constructors
298+ // 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;
302+ insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct" ) , @r#""# ) ;
303+ // 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));
306+ // Expecting a call to InnerStruct_ctor(&self->inner);
307+ // Expecting a call to InnerStruct_ctor(&self->inner2);
308+ // Expecting assignments: self->inner.a = 6; self->inner2.b = &self->c;
309+ insta:: assert_debug_snapshot!( initializer. constructors. get( "InnerStruct2" ) , @r#""# ) ;
310+ // 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));
313+ // Expecting a call to InnerStruct2_ctor(&self->inner);
314+ // Expecting a call to InnerStruct2_ctor(&self->inner2);
315+ // Expecting a call to InnerStruct2_ctor(&self->inner3);
316+ // 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;
318+ // Expecting assignments: self->inner3.inner.a = 9;
319+ insta:: assert_debug_snapshot!( initializer. constructors. get( "OuterStruct" ) , @r#""# ) ;
320+ }
321+
322+ #[ test]
323+ fn global_constructor_is_generated ( ) {
324+ let src = r#"
325+ VAR_GLOBAL
326+ gVar1 : INT := 10;
327+ gVar2 : REAL;
328+ gStructVar : MyStruct;
329+ END_VAR
330+
331+ TYPE MyStruct : STRUCT
332+ a : INT := 5;
333+ b : POINTER TO INT := ADR(gVar1);
334+ c : BOOL := TRUE;
335+ END_STRUCT
336+ "# ;
337+
338+ let diagnostician = Diagnostician :: buffered ( ) ;
339+ let mut pipeline =
340+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
341+ . unwrap ( ) ;
342+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
343+ // Visit the AST with the Initializer
344+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
345+ for unit in & project. units {
346+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
347+ }
348+ // Check for global constructor
349+ // Expecting a call to MyStruct_ctor(&gStructVar);
350+ insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
351+ }
352+
353+ #[ test]
354+ fn function_constructors_have_the_function_name ( ) {
355+ let src = r#"
356+ FUNCTION MyFunction : INT
357+ VAR
358+ localStruct : MyStruct;
359+ END_VAR
360+ END_FUNCTION
361+
362+ TYPE MyStruct : STRUCT
363+ a : INT := 5;
364+ b : BOOL := TRUE;
365+ END_STRUCT
366+ "# ;
367+
368+ let diagnostician = Diagnostician :: buffered ( ) ;
369+ let mut pipeline =
370+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
371+ . unwrap ( ) ;
372+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
373+ // Visit the AST with the Initializer
374+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
375+ for unit in & project. units {
376+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
377+ }
378+ // Check for function constructor
379+ // Expecting a call to MyStruct_ctor(&localStruct);
380+ insta:: assert_debug_snapshot!( initializer. constructors. get( "MyFunction" ) , @r#""# ) ;
381+ }
382+
383+ #[ test]
384+ fn programs_are_globals ( ) {
385+ let src = r#"
386+ PROGRAM MyProgram
387+ VAR
388+ END_VAR
389+ END_PROGRAM
390+ "# ;
391+
392+ let diagnostician = Diagnostician :: buffered ( ) ;
393+ let mut pipeline =
394+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
395+ . unwrap ( ) ;
396+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
397+ // Visit the AST with the Initializer
398+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
399+ for unit in & project. units {
400+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
401+ }
402+ // Check for program constructor
403+ // Expecting a call to MyProgram_ctor(&progStruct);
404+ insta:: assert_debug_snapshot!( initializer. global_constructor, @r#""# ) ;
405+ }
406+
407+ #[ test]
408+ fn external_structs_and_variables_are_not_initialized ( ) {
409+ let src = r#"
410+ VAR_GLOBAL
411+ internalVar : MyExtStruct;
412+ END_VAR
413+
414+ {external}
415+ VAR_GLOBAL
416+ extVar : MyExtStruct;
417+ END_VAR
418+
419+ {external}
420+ TYPE MyExtStruct : STRUCT
421+ a : INT := 5;
422+ b : BOOL := TRUE;
423+ END_STRUCT
424+ "# ;
425+
426+ let diagnostician = Diagnostician :: buffered ( ) ;
427+ let mut pipeline =
428+ plc_driver:: pipelines:: BuildPipeline :: from_sources ( "test.st" , vec ! [ ( src) ] , diagnostician)
429+ . unwrap ( ) ;
430+ let project = pipeline. parse_and_annotate ( ) . unwrap ( ) ;
431+ // Visit the AST with the Initializer
432+ let mut initializer = super :: Initializer :: new ( & project. index ) ;
433+ for unit in & project. units {
434+ initializer. visit_compilation_unit ( unit. get_unit ( ) ) ;
435+ }
436+ // Check for internal var assignment in global constructor
437+ // Expecting a call to MyExtStruct_ctor(&internalVar);
438+ // No call to MyExtStruct_ctor(&extVar);
439+ 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 ) ;
442+ insta:: assert_debug_snapshot!( initializer. constructors. get( "MyExtStruct" ) , @r#""# ) ;
443+ }
190444}
0 commit comments