Skip to content

Commit aa3b6b6

Browse files
volsaghaith
authored andcommitted
wip
1 parent 8f556ef commit aa3b6b6

File tree

7 files changed

+283
-19
lines changed

7 files changed

+283
-19
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::Assignment(_) | AstStatement::ExpressionList(_) => 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: 177 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::{
77
};
88
use plc_ast::{
99
ast::{
10-
AstFactory, AstId, AstNode, CompilationUnit, DataTypeDeclaration, Implementation, LinkageType, Pou,
11-
PouType, Variable, VariableBlock, VariableBlockType,
10+
Assignment, AstFactory, AstId, AstNode, AstStatement, CompilationUnit, DataTypeDeclaration,
11+
Implementation, LinkageType, Pou, PouType, Variable, VariableBlock, VariableBlockType,
1212
},
1313
provider::IdProvider,
1414
};
@@ -51,7 +51,7 @@ where
5151
impl<'lwr> Init<'lwr> for Initializers {
5252
fn new(candidates: &'lwr [UnresolvableConstant]) -> Self {
5353
let mut assignments = Self::default();
54-
candidates
54+
dbg!(candidates)
5555
.iter()
5656
.filter_map(|it| {
5757
if let Some(UnresolvableKind::Address(init)) = &it.kind {
@@ -88,7 +88,17 @@ impl<'lwr> Init<'lwr> for Initializers {
8888
return;
8989
}
9090

91-
assignments.insert(var_name.to_string(), initializer.clone());
91+
if let Some(init) = initializer {
92+
match init.get_stmt() {
93+
AstStatement::ExpressionList(statements) => {}
94+
AstStatement::Assignment(Assignment { left, right }) => {}
95+
_ => {
96+
assignments.insert(var_name.to_string(), initializer.clone());
97+
}
98+
}
99+
} else {
100+
assignments.insert(var_name.to_string(), initializer.clone());
101+
}
92102
}
93103

94104
fn insert_initializer(
@@ -160,6 +170,7 @@ fn create_init_unit(
160170
) -> Option<CompilationUnit> {
161171
let mut id_provider = lowerer.ctxt.id_provider.clone();
162172
let init_fn_name = get_init_fn_name(container_name);
173+
// __init_vtable-child
163174
let (is_stateless, is_extensible, location) = lowerer
164175
.index
165176
.find_pou(container_name)
@@ -196,7 +207,7 @@ fn create_init_unit(
196207

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

src/resolver/const_evaluator.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,31 @@ fn evaluate_with_target_hint(
526526
}
527527
}
528528
AstStatement::ExpressionList(expressions) => {
529+
//TODO: If an expression failed to resolve as Address, mark the full list as unresolvable
529530
let inner_elements = expressions
530531
.iter()
531532
.map(|e| evaluate(e, scope, index))
532-
.collect::<Result<Vec<Option<AstNode>>, UnresolvableKind>>()?
533-
.into_iter()
534-
.collect::<Option<Vec<AstNode>>>();
533+
.collect::<Result<Vec<Option<AstNode>>, UnresolvableKind>>();
534+
let inner_elements = match inner_elements {
535+
Ok(inner_elements) => inner_elements.into_iter().collect::<Option<Vec<AstNode>>>(),
536+
Err(UnresolvableKind::Address(adr)) => {
537+
dbg!(adr);
538+
//return the entire expression as unresolvable
539+
return Err(UnresolvableKind::Address(InitData {
540+
initializer: Some(AstNode::new(
541+
AstStatement::ExpressionList(expressions.to_owned()),
542+
id,
543+
location,
544+
)),
545+
target_type_name: target_type.map(|it| it.to_string()),
546+
scope: scope.map(|it| it.to_string()),
547+
lhs: lhs.map(|it| it.to_string()),
548+
}));
549+
}
550+
Err(any) => {
551+
return Err(any);
552+
}
553+
};
535554

536555
//return a new array, or return none if one was not resolvable
537556
inner_elements.map(|ie| AstNode::new(AstStatement::ExpressionList(ie), id, location))
@@ -560,11 +579,15 @@ fn evaluate_with_target_hint(
560579
}
561580
AstStatement::Assignment(data) => {
562581
//Right needs evaluation
563-
if let Some(right) = evaluate(&data.right, scope, index)? {
564-
Some(AstFactory::create_assignment(*data.left.clone(), right, id))
565-
} else {
566-
Some(initial.clone())
567-
}
582+
match evaluate(&data.right, scope, index) {
583+
Ok(Some(value)) => Ok(Some(AstFactory::create_assignment(*data.left.clone(), value, id))),
584+
Ok(None) => Ok(Some(initial.clone())),
585+
Err(UnresolvableKind::Address(mut init)) => {
586+
init.lhs = data.left.get_flat_reference_name().map(|it| it.to_string());
587+
Err(UnresolvableKind::Address(init))
588+
}
589+
Err(why) => Err(why),
590+
}?
568591
}
569592
AstStatement::RangeStatement(data) => {
570593
let start = evaluate(&data.start, scope, index)?.unwrap_or_else(|| *data.start.to_owned());

0 commit comments

Comments
 (0)