Skip to content

Commit 2e615e8

Browse files
volsaghaith
authored andcommitted
wip
1 parent 8f556ef commit 2e615e8

File tree

6 files changed

+239
-7
lines changed

6 files changed

+239
-7
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: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ impl InitVisitor {
163163
})
164164
})
165165
}),
166+
AstStatement::ExpressionList(statements) => None,
166167
_ => return,
167168
};
168169

@@ -304,8 +305,13 @@ impl InitVisitor {
304305
.and_then(|it| it.swap_remove(var.get_type_name()))
305306
.map(|node| (var.get_name(), node))
306307
})
308+
// .map(|node| (node.get_name(), node))
307309
.collect::<Vec<_>>();
308310

311+
if user_type.data_type.get_name().is_some_and(|opt| opt == "vtable_child") {
312+
(&user_type, &member_inits);
313+
}
314+
309315
for (lhs, init) in member_inits {
310316
// update struct member initializers
311317
self.unresolved_initializers.maybe_insert_initializer(name, Some(lhs), &init);
@@ -436,13 +442,16 @@ fn create_assignment_if_necessary(
436442
base_ident: Option<&str>,
437443
rhs: &Option<AstNode>,
438444
mut id_provider: IdProvider,
439-
) -> Option<AstNode> {
445+
) -> Vec<AstNode> {
440446
let lhs = create_member_reference(
441447
lhs_ident,
442448
id_provider.clone(),
443449
base_ident.map(|id| create_member_reference(id, id_provider.clone(), None)),
444450
);
445-
rhs.as_ref().map(|node| AstFactory::create_assignment(lhs, node.to_owned(), id_provider.next_id()))
451+
rhs.as_ref()
452+
.map(|node| AstFactory::create_assignment(lhs, node.to_owned(), id_provider.next_id()))
453+
.map(|node| vec![node])
454+
.unwrap_or_else(|| vec![])
446455
}
447456

448457
fn create_ref_assignment(

src/lowering/initializers.rs

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ impl<'lwr> Init<'lwr> for Initializers {
7878
var_name: Option<&str>,
7979
initializer: &Option<AstNode>,
8080
) {
81+
dbg!(container_name, var_name, initializer);
82+
panic!("Name is none");
8183
let assignments = self.entry(container_name.to_string()).or_default();
8284
let Some(var_name) = var_name else {
8385
return;
@@ -160,6 +162,7 @@ fn create_init_unit(
160162
) -> Option<CompilationUnit> {
161163
let mut id_provider = lowerer.ctxt.id_provider.clone();
162164
let init_fn_name = get_init_fn_name(container_name);
165+
// __init_vtable-child
163166
let (is_stateless, is_extensible, location) = lowerer
164167
.index
165168
.find_pou(container_name)
@@ -196,7 +199,7 @@ fn create_init_unit(
196199

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

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)