Skip to content

Commit 78cd38e

Browse files
authored
refactor: Introduce StatementAnnotation::Argument (#1470)
Identical to `StatementAnnotation::Value` with an additional `position` field indicating the position of a parameter in an POU. Helpful for codegen later on when generating the arguments of a function call for implicit calls.
1 parent d7b445a commit 78cd38e

File tree

11 files changed

+315
-52
lines changed

11 files changed

+315
-52
lines changed

compiler/plc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1269,13 +1269,13 @@ impl AstNode {
12691269
pub fn has_super_metadata(&self) -> bool {
12701270
self.get_metadata()
12711271
.or_else(|| self.get_identifier().and_then(|it| it.get_metadata()))
1272-
.map_or(false, |it| it.is_super())
1272+
.is_some_and(|it| it.is_super())
12731273
}
12741274

12751275
pub fn has_super_metadata_deref(&self) -> bool {
12761276
self.get_metadata()
12771277
.or_else(|| self.get_identifier().and_then(|it| it.get_metadata()))
1278-
.map_or(false, |it| it.is_super_deref())
1278+
.is_some_and(|it| it.is_super_deref())
12791279
}
12801280

12811281
pub fn can_be_assigned_to(&self) -> bool {

src/codegen/generators/expression_generator.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,11 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
590590
self.assign_output_value(&CallParameterAssignment {
591591
assignment: assignment_statement,
592592
function_name,
593-
index: index as u32,
593+
index: self
594+
.annotations
595+
.get_hint(assignment_statement)
596+
.and_then(StatementAnnotation::get_location_in_parent)
597+
.expect("arguments must have a type hint"),
594598
parameter_struct,
595599
})?
596600
}
@@ -886,14 +890,14 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
886890
fn generate_function_arguments(
887891
&self,
888892
pou: &PouIndexEntry,
889-
passed_parameters: &[&AstNode],
893+
arguments: &[&AstNode],
890894
declared_parameters: Vec<&VariableIndexEntry>,
891895
) -> Result<Vec<BasicMetadataValueEnum<'ink>>, Diagnostic> {
892896
let mut result = Vec::new();
893897
let mut variadic_parameters = Vec::new();
894898
let mut passed_param_indices = Vec::new();
895-
for (i, parameter) in passed_parameters.iter().enumerate() {
896-
let (i, parameter, _) = get_implicit_call_parameter(parameter, &declared_parameters, i)?;
899+
for (i, argument) in arguments.iter().enumerate() {
900+
let (i, parameter, _) = get_implicit_call_parameter(argument, &declared_parameters, i)?;
897901

898902
// parameter_info includes the declaration type and type name
899903
let parameter_info = declared_parameters
@@ -1155,18 +1159,22 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
11551159
pou_name: &str,
11561160
class_struct: Option<PointerValue<'ink>>,
11571161
parameter_struct: PointerValue<'ink>,
1158-
passed_parameters: &[&AstNode],
1162+
arguments: &[&AstNode],
11591163
) -> Result<Vec<BasicMetadataValueEnum<'ink>>, Diagnostic> {
11601164
let mut result = class_struct
11611165
.map(|class_struct| {
11621166
vec![class_struct.as_basic_value_enum().into(), parameter_struct.as_basic_value_enum().into()]
11631167
})
11641168
.unwrap_or_else(|| vec![parameter_struct.as_basic_value_enum().into()]);
1165-
for (i, stmt) in passed_parameters.iter().enumerate() {
1169+
for argument in arguments.iter() {
11661170
let parameter = self.generate_call_struct_argument_assignment(&CallParameterAssignment {
1167-
assignment: stmt,
1171+
assignment: argument,
11681172
function_name: pou_name,
1169-
index: i as u32,
1173+
index: self
1174+
.annotations
1175+
.get_hint(argument)
1176+
.and_then(StatementAnnotation::get_location_in_parent)
1177+
.expect("arguments must have a type hint"),
11701178
parameter_struct,
11711179
})?;
11721180
if let Some(parameter) = parameter {

src/codegen/tests/directaccess_test.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn direct_acess_in_output_assignment_implicit_explicit_and_mixed() {
141141
",
142142
);
143143

144-
assert_snapshot!(ir, @r#"
144+
assert_snapshot!(ir, @r###"
145145
; ModuleID = '<internal>'
146146
source_filename = "<internal>"
147147
@@ -218,7 +218,7 @@ fn direct_acess_in_output_assignment_implicit_explicit_and_mixed() {
218218
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
219219
220220
attributes #0 = { argmemonly nofree nounwind willreturn }
221-
"#);
221+
"###);
222222
}
223223

224224
#[test]
@@ -305,7 +305,7 @@ fn direct_acess_in_output_assignment_with_simple_expression_implicit() {
305305
",
306306
);
307307

308-
assert_snapshot!(ir, @r#"
308+
assert_snapshot!(ir, @r###"
309309
; ModuleID = '<internal>'
310310
source_filename = "<internal>"
311311
@@ -344,7 +344,7 @@ fn direct_acess_in_output_assignment_with_simple_expression_implicit() {
344344
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
345345
346346
attributes #0 = { argmemonly nofree nounwind willreturn }
347-
"#);
347+
"###);
348348
}
349349

350350
#[test]

src/codegen/tests/parameters_tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ fn by_value_fb_arg_aggregates_are_memcopied() {
10251025
"#,
10261026
);
10271027

1028-
assert_snapshot!(result, @r#"
1028+
assert_snapshot!(result, @r###"
10291029
; ModuleID = '<internal>'
10301030
source_filename = "<internal>"
10311031
@@ -1077,7 +1077,7 @@ fn by_value_fb_arg_aggregates_are_memcopied() {
10771077
10781078
attributes #0 = { argmemonly nofree nounwind willreturn writeonly }
10791079
attributes #1 = { argmemonly nofree nounwind willreturn }
1080-
"#);
1080+
"###);
10811081
}
10821082

10831083
#[test]

src/index.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -700,24 +700,19 @@ pub enum PouIndexEntry {
700700
}
701701

702702
impl PouIndexEntry {
703-
pub fn get_method_name(&self) -> String {
703+
pub fn get_method_name(&self) -> Option<String> {
704704
match self {
705705
PouIndexEntry::Method { property: Some((name, kind)), .. } => {
706706
let kind = kind.to_string().to_uppercase();
707-
format!("Property `{name}` ({kind})")
707+
Some(format!("Property `{name}` ({kind})"))
708708
}
709709

710710
PouIndexEntry::Method { name, .. } => {
711711
let name = name.rsplit_once('.').map(|(_, rhs)| rhs).unwrap_or_default();
712-
format!("Method `{name}`")
712+
Some(format!("Method `{name}`"))
713713
}
714714

715-
_ => unreachable!(
716-
"
717-
*>yfw reading the name of this method*
718-
https://i.pinimg.com/originals/47/8c/fe/478cfec0807b19eb0d96073c0301c82d.gif
719-
"
720-
),
715+
_ => None,
721716
}
722717
}
723718
}

src/resolver.rs

+56-23
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,14 @@ impl TypeAnnotator<'_> {
304304
} else {
305305
vec![]
306306
};
307-
let operator_qualifier = &self.get_call_name(operator);
308307

309308
let mut generics_candidates: FxHashMap<String, Vec<String>> = FxHashMap::default();
310309
let mut params = vec![];
311310
let mut parameters = parameters.into_iter();
312311

313312
// If we are dealing with an action call statement, we need to get the declared parameters from the parent POU in order
314313
// to annotate them with the correct type hint.
314+
let operator_qualifier = &self.get_call_name(operator);
315315
let implementation = self.index.find_implementation_by_name(operator_qualifier);
316316
let operator_qualifier = implementation.map(|it| it.get_type_name()).unwrap_or(operator_qualifier);
317317
for m in self.index.get_declared_parameters(operator_qualifier).into_iter() {
@@ -322,7 +322,7 @@ impl TypeAnnotator<'_> {
322322
{
323323
generics_candidates.entry(key.to_string()).or_default().push(candidate.to_string())
324324
} else {
325-
params.push((p, type_name.to_string()))
325+
params.push((p, type_name.to_string(), m.get_location_in_parent()))
326326
}
327327
}
328328
}
@@ -331,9 +331,8 @@ impl TypeAnnotator<'_> {
331331
match self.index.find_pou(operator_qualifier) {
332332
Some(pou) if pou.is_variadic() => {
333333
//get variadic argument type, if it is generic, update the generic candidates
334-
if let Some(type_name) =
335-
self.index.get_variadic_member(pou.get_name()).map(VariableIndexEntry::get_type_name)
336-
{
334+
if let Some(variadic) = self.index.get_variadic_member(pou.get_name()) {
335+
let type_name = variadic.get_type_name();
337336
for parameter in parameters {
338337
if let Some((key, candidate)) = TypeAnnotator::get_generic_candidate(
339338
self.index,
@@ -383,17 +382,23 @@ impl TypeAnnotator<'_> {
383382
type_name
384383
};
385384

386-
params.push((parameter, type_name.to_string()));
385+
params.push((
386+
parameter,
387+
type_name.to_string(),
388+
variadic.get_location_in_parent(),
389+
));
387390
}
388391
}
389392
}
390393
}
391394
_ => {}
392395
}
393-
for (p, name) in params {
394-
self.annotate_parameters(p, &name);
396+
397+
for (p, name, position) in params {
398+
self.annotate_parameters(p, &name, position as usize);
395399
}
396-
//Attempt to resolve the generic signature here
400+
401+
// Attempt to resolve the generic signature here
397402
self.update_generic_call_statement(
398403
generics_candidates,
399404
operator_qualifier,
@@ -437,6 +442,14 @@ pub enum StatementAnnotation {
437442
Value {
438443
resulting_type: String,
439444
},
445+
/// An argument of a call statement
446+
Argument {
447+
/// The resulting type of this argument
448+
resulting_type: String,
449+
450+
/// The position of the parameter this argument is assigned to
451+
position: usize,
452+
},
440453
/// a reference that resolves to a declared variable (e.g. `a` --> `PLC_PROGRAM.a`)
441454
Variable {
442455
/// the name of the variable's type (e.g. `"INT"`)
@@ -717,6 +730,27 @@ impl StatementAnnotation {
717730
_ => None,
718731
}
719732
}
733+
734+
/// Returns the location of a parameter in some POU the argument is assigned to, for example
735+
/// `foo(a, b, c)` will return `0` for `a`, `1` for `b` and `3` for c if `foo` has the following variable
736+
/// blocks
737+
/// ```norun
738+
/// VAR_INPUT
739+
/// a, b : DINT;
740+
/// END_VAR
741+
/// VAR
742+
/// placeholder: DINT;
743+
/// END_VAR
744+
/// VAR_INPUT
745+
/// c : DINT;
746+
/// END_VAR`
747+
/// ```
748+
pub(crate) fn get_location_in_parent(&self) -> Option<u32> {
749+
match self {
750+
StatementAnnotation::Argument { position, .. } => Some(*position as u32),
751+
_ => None,
752+
}
753+
}
720754
}
721755

722756
impl From<&PouIndexEntry> for StatementAnnotation {
@@ -807,6 +841,7 @@ pub trait AnnotationMap {
807841
fn get_type_name_for_annotation<'a>(&'a self, annotation: &'a StatementAnnotation) -> Option<&'a str> {
808842
match annotation {
809843
StatementAnnotation::Value { resulting_type } => Some(resulting_type.as_str()),
844+
StatementAnnotation::Argument { resulting_type, .. } => Some(resulting_type.as_str()),
810845
StatementAnnotation::Variable { resulting_type, .. } => Some(resulting_type.as_str()),
811846
StatementAnnotation::ReplacementAst { statement } => self
812847
.get_hint(statement)
@@ -2133,10 +2168,9 @@ impl<'i> TypeAnnotator<'i> {
21332168
}
21342169
StatementAnnotation::Program { qualified_name } => Some(qualified_name.clone()),
21352170
StatementAnnotation::Variable { resulting_type, .. } => {
2136-
//lets see if this is a FB
21372171
self.index
21382172
.find_pou(resulting_type.as_str())
2139-
.filter(|it| matches!(it, PouIndexEntry::FunctionBlock { .. }))
2173+
.filter(|it| matches!(it, PouIndexEntry::FunctionBlock { .. } | PouIndexEntry::Program { .. }))
21402174
.map(|it| it.get_name().to_string())
21412175
}
21422176
// call statements on array access "arr[1]()" will return a StatementAnnotation::Value
@@ -2158,18 +2192,17 @@ impl<'i> TypeAnnotator<'i> {
21582192
operator_qualifier
21592193
}
21602194

2161-
pub(crate) fn annotate_parameters(&mut self, p: &AstNode, type_name: &str) {
2162-
if !matches!(
2163-
p.get_stmt(),
2164-
AstStatement::Assignment(..)
2165-
| AstStatement::OutputAssignment(..)
2166-
| AstStatement::RefAssignment(..)
2167-
) {
2168-
if let Some(effective_member_type) = self.index.find_effective_type_by_name(type_name) {
2169-
//update the type hint
2170-
self.annotation_map
2171-
.annotate_type_hint(p, StatementAnnotation::value(effective_member_type.get_name()))
2172-
}
2195+
pub(crate) fn annotate_parameters(&mut self, p: &AstNode, type_name: &str, position: usize) {
2196+
if let Some(effective_member_type) = self.index.find_effective_type_by_name(type_name) {
2197+
//update the type hint
2198+
// self.annotation_map.annotate_type_hint(p, StatementAnnotation::value(effective_member_type.get_name()))
2199+
self.annotation_map.annotate_type_hint(
2200+
p,
2201+
StatementAnnotation::Argument {
2202+
resulting_type: effective_member_type.get_name().to_string(),
2203+
position,
2204+
},
2205+
);
21732206
}
21742207
}
21752208

0 commit comments

Comments
 (0)