Skip to content

Commit dcc0be6

Browse files
committed
wip
1 parent 32300eb commit dcc0be6

File tree

2 files changed

+132
-47
lines changed

2 files changed

+132
-47
lines changed

compiler/plc_ast/src/ast.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,14 @@ impl VariableBlock {
551551
self.variables = variables;
552552
self
553553
}
554+
555+
pub fn is_local(&self) -> bool {
556+
matches!(self.kind, VariableBlockType::Local)
557+
}
558+
559+
pub fn is_temp(&self) -> bool {
560+
matches!(self.kind, VariableBlockType::Temp)
561+
}
554562
}
555563

556564
impl Default for VariableBlock {

compiler/plc_lowering/src/initializer.rs

Lines changed: 124 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,18 @@
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)]
2737
enum Body {
@@ -31,20 +41,20 @@ enum Body {
3141
}
3242

3343
pub 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

76101
impl 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

82113
mod 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

Comments
 (0)