Skip to content

Commit 734cd9d

Browse files
committed
wip
1 parent 8f556ef commit 734cd9d

File tree

6 files changed

+231
-6
lines changed

6 files changed

+231
-6
lines changed

compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ lazy_static! {
138138
E034, Error, include_str!("./error_codes/E034.md"),
139139
E035, Error, include_str!("./error_codes/E035.md"),
140140
E036, Error, include_str!("./error_codes/E036.md"),
141-
E037, Error, include_str!("./error_codes/E037.md"),
141+
E037, Warning, include_str!("./error_codes/E037.md"),
142142
E038, Error, include_str!("./error_codes/E038.md"), // Missing type
143143
E039, Warning, include_str!("./error_codes/E039.md"),
144144
E040, Error, include_str!("./error_codes/E040.md"),

compiler/plc_driver/src/pipelines.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,12 @@ impl AnnotatedUnit {
636636
}
637637
}
638638

639+
impl From<AnnotatedUnit> for CompilationUnit {
640+
fn from(value: AnnotatedUnit) -> Self {
641+
value.unit
642+
}
643+
}
644+
639645
/// A project that has been annotated with information about different types and used units
640646
pub struct AnnotatedProject {
641647
pub units: Vec<AnnotatedUnit>,

src/codegen/tests/initialization_test/type_initializers.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,3 +638,41 @@ fn skipped_field_members_for_array_of_structs_are_zero_initialized() {
638638

639639
insta::assert_snapshot!(res);
640640
}
641+
642+
#[test]
643+
fn struct_initializer_with_pointer_assignment() {
644+
let res = codegen(
645+
r"
646+
VAR_GLOBAL
647+
foo : DINT := 1;
648+
bar : DINT := 2;
649+
baz : DINT := 3;
650+
END_VAR
651+
652+
TYPE vtable_parent : STRUCT
653+
foo : REF_TO DINT := REF(foo);
654+
bar : REF_TO DINT := REF(bar);
655+
END_STRUCT END_TYPE
656+
657+
TYPE vtable_child : STRUCT
658+
__vtable_parent : vtable_parent := (foo := REF(foo));
659+
bar : REF_TO DINT := REF(bar);
660+
baz : REF_TO DINT := REF(baz);
661+
END_STRUCT END_TYPE
662+
",
663+
);
664+
665+
insta::assert_snapshot!(res, @r###"
666+
; ModuleID = '<internal>'
667+
source_filename = "<internal>"
668+
669+
%vtable_parent = type { i32*, i32*, i32 }
670+
%vtable_child = type { %vtable_parent, i32*, i32* }
671+
672+
@foo = global i32 1
673+
@bar = global i32 2
674+
@baz = global i32 3
675+
@__vtable_parent__init = unnamed_addr constant %vtable_parent zeroinitializer
676+
@__vtable_child__init = unnamed_addr constant %vtable_child { %vtable_parent { i32* null, i32* null, i32 1 }, i32* null, i32* null }
677+
"###);
678+
}

src/lowering.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,7 @@ impl InitVisitor {
292292
};
293293
let name = ty.get_name();
294294

295-
let member_inits = self
296-
.index
297-
.get_container_members(name)
295+
let member_inits = dbg!(self.index.get_container_members(name))
298296
.iter()
299297
.filter_map(|var| {
300298
// struct member initializers don't have a qualifier/scope while evaluated in `const_evaluator.rs` and are registered as globals under their data-type name;
@@ -304,8 +302,13 @@ impl InitVisitor {
304302
.and_then(|it| it.swap_remove(var.get_type_name()))
305303
.map(|node| (var.get_name(), node))
306304
})
305+
// .map(|node| (node.get_name(), node))
307306
.collect::<Vec<_>>();
308307

308+
if user_type.data_type.get_name().is_some_and(|opt| opt == "vtable_child") {
309+
dbg!(&user_type, &member_inits);
310+
}
311+
309312
for (lhs, init) in member_inits {
310313
// update struct member initializers
311314
self.unresolved_initializers.maybe_insert_initializer(name, Some(lhs), &init);

src/lowering/initializers.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ fn create_init_unit(
160160
) -> Option<CompilationUnit> {
161161
let mut id_provider = lowerer.ctxt.id_provider.clone();
162162
let init_fn_name = get_init_fn_name(container_name);
163+
// __init_vtable-child
163164
let (is_stateless, is_extensible, location) = lowerer
164165
.index
165166
.find_pou(container_name)
@@ -194,6 +195,7 @@ fn create_init_unit(
194195

195196
let init_pou = new_pou(&init_fn_name, id_provider.next_id(), param, PouType::Init, &location);
196197

198+
// dbg!(&assignments);
197199
let mut statements = assignments
198200
.iter()
199201
.filter_map(|(lhs_name, initializer)| {
@@ -510,3 +512,162 @@ fn new_unit(pou: Pou, implementation: Implementation, file_name: &'static str) -
510512
pub(super) fn get_user_init_fn_name(type_name: &str) -> String {
511513
format!("__user_init_{}", type_name)
512514
}
515+
516+
// TODO: Is this the correct location? Are there not any other initializer tests we can move this module to?
517+
#[cfg(test)]
518+
mod tests {
519+
use test_utils::parse_and_validate_buffered_ast;
520+
521+
#[test]
522+
fn struct_initializer_with_pointer_assignment() {
523+
let source = r"
524+
VAR_GLOBAL
525+
foo : DINT := 1;
526+
bar : DINT := 2;
527+
baz : DINT := 3;
528+
END_VAR
529+
530+
TYPE vtable_parent : STRUCT
531+
foo : REF_TO DINT := REF(foo);
532+
bar : REF_TO DINT := REF(bar);
533+
END_STRUCT END_TYPE
534+
535+
TYPE vtable_child : STRUCT
536+
__vtable_parent : vtable_parent := (foo := REF(foo));
537+
bar : REF_TO DINT := REF(bar);
538+
baz : REF_TO DINT := REF(baz);
539+
END_STRUCT END_TYPE
540+
";
541+
542+
let units = parse_and_validate_buffered_ast(source);
543+
insta::assert_debug_snapshot!(units[1].implementations[1], @r###"
544+
Implementation {
545+
name: "__init_vtable_child",
546+
type_name: "__init_vtable_child",
547+
linkage: Internal,
548+
pou_type: Init,
549+
statements: [
550+
Assignment {
551+
left: ReferenceExpr {
552+
kind: Member(
553+
Identifier {
554+
name: "bar",
555+
},
556+
),
557+
base: Some(
558+
ReferenceExpr {
559+
kind: Member(
560+
Identifier {
561+
name: "self",
562+
},
563+
),
564+
base: None,
565+
},
566+
),
567+
},
568+
right: CallStatement {
569+
operator: ReferenceExpr {
570+
kind: Member(
571+
Identifier {
572+
name: "REF",
573+
},
574+
),
575+
base: None,
576+
},
577+
parameters: Some(
578+
ReferenceExpr {
579+
kind: Member(
580+
Identifier {
581+
name: "bar",
582+
},
583+
),
584+
base: None,
585+
},
586+
),
587+
},
588+
},
589+
Assignment {
590+
left: ReferenceExpr {
591+
kind: Member(
592+
Identifier {
593+
name: "baz",
594+
},
595+
),
596+
base: Some(
597+
ReferenceExpr {
598+
kind: Member(
599+
Identifier {
600+
name: "self",
601+
},
602+
),
603+
base: None,
604+
},
605+
),
606+
},
607+
right: CallStatement {
608+
operator: ReferenceExpr {
609+
kind: Member(
610+
Identifier {
611+
name: "REF",
612+
},
613+
),
614+
base: None,
615+
},
616+
parameters: Some(
617+
ReferenceExpr {
618+
kind: Member(
619+
Identifier {
620+
name: "baz",
621+
},
622+
),
623+
base: None,
624+
},
625+
),
626+
},
627+
},
628+
CallStatement {
629+
operator: ReferenceExpr {
630+
kind: Member(
631+
Identifier {
632+
name: "__init_vtable_parent",
633+
},
634+
),
635+
base: None,
636+
},
637+
parameters: Some(
638+
ReferenceExpr {
639+
kind: Member(
640+
Identifier {
641+
name: "__vtable_parent",
642+
},
643+
),
644+
base: Some(
645+
ReferenceExpr {
646+
kind: Member(
647+
Identifier {
648+
name: "self",
649+
},
650+
),
651+
base: None,
652+
},
653+
),
654+
},
655+
),
656+
},
657+
],
658+
location: SourceLocation {
659+
span: Range(12:17 - 12:29),
660+
},
661+
name_location: SourceLocation {
662+
span: Range(12:17 - 12:29),
663+
},
664+
end_location: SourceLocation {
665+
span: Range(12:17 - 12:29),
666+
},
667+
overriding: false,
668+
generic: false,
669+
access: None,
670+
}
671+
"###);
672+
}
673+
}

tests/test_utils/src/lib.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use std::io::Read;
22

3-
use driver::{cli, pipelines::BuildPipeline};
3+
use driver::{
4+
cli,
5+
pipelines::{AnnotatedProject, BuildPipeline},
6+
};
47
use plc::{linker::LinkerType, DebugLevel};
5-
use plc_diagnostics::diagnostician::Diagnostician;
8+
use plc_ast::ast::CompilationUnit;
9+
use plc_diagnostics::{diagnostician::Diagnostician, reporter::DiagnosticReporter};
610
use plc_index::GlobalContext;
711
use plc_source::SourceCode;
812
use project::project::Project;
@@ -27,6 +31,19 @@ pub fn parse_and_validate_buffered(src: &str) -> String {
2731
driver::parse_and_validate("TestProject", vec![source])
2832
}
2933

34+
pub fn parse_and_validate_buffered_ast(src: &str) -> Vec<CompilationUnit> {
35+
let source: SourceCode = src.into();
36+
37+
match driver::parse_and_annotate_with_diagnostics("TestProject", vec![source], Diagnostician::buffered())
38+
{
39+
Ok((mut pipeline, project)) => {
40+
project.validate(&pipeline.context, &mut pipeline.diagnostician).unwrap();
41+
project.units.into_iter().map(CompilationUnit::from).collect()
42+
}
43+
Err(diagnostician) => panic!("{}", diagnostician.buffer().unwrap()),
44+
}
45+
}
46+
3047
fn get_debug_param(debug_level: DebugLevel) -> Option<String> {
3148
match debug_level {
3249
DebugLevel::None => None,

0 commit comments

Comments
 (0)