Skip to content

Commit

Permalink
convert correctness tests to lit
Browse files Browse the repository at this point in the history
  • Loading branch information
volsa committed Jul 1, 2024
1 parent a991a8c commit 64b759a
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 162 deletions.
28 changes: 17 additions & 11 deletions src/validation/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,20 +777,26 @@ fn validate_ref_assignment<T: AnnotationMap>(
assignment: &Assignment,
assignment_location: &SourceLocation,
) {
// Assert that the rhs is a variable that can be referenced
if !assignment.right.is_reference() {
validator.push_diagnostic(
Diagnostic::new("Invalid assignment, expected a reference")
.with_location(&assignment.right.location)
.with_error_code("E098"),
);
}
let mut assert_reference = |node: &AstNode| {
if !node.is_reference() {
validator.push_diagnostic(
Diagnostic::new("Invalid assignment, expected a reference")
.with_location(&node.location)
.with_error_code("E098"),
);
}
};

assert_reference(&assignment.left);
assert_reference(&assignment.right);

// Lastly, assert the type the lhs references matches with the rhs
let type_lhs = context.annotations.get_type(&assignment.left, context.index).unwrap();
let type_rhs = context.annotations.get_type(&assignment.right, context.index).unwrap();
let type_lhs = context.annotations.get_type_or_void(&assignment.left, context.index);
let type_rhs = context.annotations.get_type_or_void(&assignment.right, context.index);
let type_info_lhs = context.index.find_elementary_pointer_type(type_lhs.get_type_information());
let type_info_rhs = context.index.find_elementary_pointer_type(type_rhs.get_type_information());

if type_lhs != type_rhs {
if type_info_lhs != type_info_rhs {
validator.push_diagnostic(
Diagnostic::new(format!(
"Invalid assignment, types {} and {} differ",
Expand Down
15 changes: 8 additions & 7 deletions src/validation/tests/assignment_validation_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,11 +1246,12 @@ fn reference_to_variables_and_ref_assignments() {
referenceToFooInitializedArray : REFERENCE TO ARRAY[1..5] OF DINT;
END_VAR
referenceToFoo REF= foo;
refToFoo REF= foo;
referenceToFoo REF= foo;
// Invalid
1 REF= foo;
foo REF= foo;
refToFoo REF= foo;
referenceToFoo REF= 0;
referenceToFoo REF= referenceToFoo;
END_FUNCTION
Expand Down Expand Up @@ -1293,16 +1294,16 @@ fn reference_to_variables_and_ref_assignments() {
│ │
│ REFERENCE TO variables can not reference arrays, pointers or bits
error[E098]: Invalid assignment, types REF_TO DINT and DINT differ
error[E098]: Invalid assignment, expected a reference
┌─ <internal>:30:13
30 │ refToFoo REF= foo;
│ ^^^^^^^^^^^^^^^^^ Invalid assignment, types REF_TO DINT and DINT differ
30 │ 1 REF= foo;
│ ^ Invalid assignment, expected a reference
error[E098]: Invalid assignment, expected a reference
┌─ <internal>:31:33
┌─ <internal>:32:33
31 │ referenceToFoo REF= 0;
32 │ referenceToFoo REF= 0;
│ ^ Invalid assignment, expected a reference
"###);
Expand Down
81 changes: 42 additions & 39 deletions src/validation/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,49 +217,52 @@ fn validate_reference_to_declaration<T: AnnotationMap>(
variable: &Variable,
variable_entry: &VariableIndexEntry,
) {
if let Some(variable_type) = context.index.find_effective_type_by_name(variable_entry.get_type_name()) {
if variable_type.get_type_information().is_reference_to() {
let DataTypeInformation::Pointer { inner_type_name, .. } = variable_type.get_type_information()
else {
unreachable!("`REFERENCE TO` is defined as a pointer, hence this must exist")
};
let Some(variable_ty) = context.index.find_effective_type_by_name(variable_entry.get_type_name()) else {
return;
};

// Assert that no initializers are present in the `REFERENCE TO` declaration
if let Some(ref initializer) = variable.initializer {
if variable_type.get_type_information().is_reference_to() {
validator.push_diagnostic(
Diagnostic::new("Initializations of REFERENCE TO variables are disallowed")
.with_location(&initializer.location)
.with_error_code("E099"),
);
}
}
if !variable_ty.get_type_information().is_reference_to() {
return;
}

// Assert that the referenced type is no variable reference
let qualifier = context.qualifier.unwrap_or_default();
let inner_ty_is_local_var = context.index.find_member(qualifier, inner_type_name).is_some();
let inner_ty_is_global_var = context.index.find_global_variable(inner_type_name).is_some();
let Some(inner_ty_name) = variable_ty.get_type_information().get_inner_pointer_type_name() else {
unreachable!("`REFERENCE TO` is defined as a pointer, hence this must exist")
};

if inner_ty_is_local_var || inner_ty_is_global_var {
validator.push_diagnostic(
Diagnostic::new("REFERENCE TO variables can not reference other variables")
.with_location(&variable_type.location)
.with_error_code("E099"),
);
}
// Assert that no initializers are present in the `REFERENCE TO` declaration
if let Some(ref initializer) = variable.initializer {
if variable_ty.get_type_information().is_reference_to() {
validator.push_diagnostic(
Diagnostic::new("Initializations of REFERENCE TO variables are disallowed")
.with_location(&initializer.location)
.with_error_code("E099"),
);
}
}

// Lastly assert that the referenced type is no array, pointer or bit
let inner_type = context.index.find_effective_type_by_name(inner_type_name);
if let Some(ty) = inner_type {
if ty.is_array() || ty.is_pointer() || ty.is_bit() {
validator.push_diagnostic(
Diagnostic::new("REFERENCE TO variables can not reference arrays, pointers or bits")
.with_location(&variable.location)
.with_secondary_location(&ty.location)
.with_error_code("E099"),
);
}
}
// Assert that the referenced type is no variable reference
let qualifier = context.qualifier.unwrap_or_default();
let inner_ty_is_local_var = context.index.find_member(qualifier, inner_ty_name).is_some();
let inner_ty_is_global_var = context.index.find_global_variable(inner_ty_name).is_some();

if inner_ty_is_local_var || inner_ty_is_global_var {
validator.push_diagnostic(
Diagnostic::new("REFERENCE TO variables can not reference other variables")
.with_location(&variable_ty.location)
.with_error_code("E099"),
);
}

// Lastly assert that the referenced type is no array, pointer or bit
let inner_type = context.index.find_effective_type_by_name(inner_ty_name);
if let Some(ty) = inner_type {
if ty.is_array() || ty.is_pointer() || ty.is_bit() {
validator.push_diagnostic(
Diagnostic::new("REFERENCE TO variables can not reference arrays, pointers or bits")
.with_location(&variable.location)
.with_secondary_location(&ty.location)
.with_error_code("E099"),
);
}
}
}
Expand Down
105 changes: 0 additions & 105 deletions tests/correctness/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,108 +242,3 @@ fn value_behind_function_block_pointer_is_assigned_to_correctly() {
assert!(!maintype.a);
assert!(maintype.b);
}

#[test]
fn reference_assignment() {
let function = r"
FUNCTION main : DINT
VAR
a : REF_TO DINT;
b : DINT := 5;
END_VAR
a REF= b;
main := a^;
END_FUNCTION
";

let res: i32 = compile_and_run(function.to_string(), &mut MainType::default());
assert_eq!(5, res);
}

#[test]
fn reference_to_assignment() {
let function = r"
FUNCTION main : DINT
VAR
a : REFERENCE TO DINT;
b : DINT := 5;
END_VAR
a REF= b;
main := a;
END_FUNCTION
";

let res: i32 = compile_and_run(function, &mut MainType::default());
assert_eq!(5, res);
}

#[test]
fn reference_to_variable_referencing_other_reference_to_variable() {
let function = r"
FUNCTION main : DINT
VAR
foo : REFERENCE TO DINT;
bar : REFERENCE TO DINT;
qux : DINT;
END_VAR
bar REF= qux;
foo REF= bar;
qux := 5;
main := foo; // foo -> bar -> qux
END_FUNCTION
";

let res: i32 = compile_and_run(function, &mut MainType::default());
assert_eq!(5, res);
}

#[test]
fn reference_to_variable_referencing_itself() {
let function = r"
FUNCTION main : DINT
VAR
foo : REFERENCE TO DINT;
bar : REFERENCE TO DINT;
qux : DINT;
END_VAR
foo REF= bar;
bar REF= qux;
bar REF= bar;
qux := 5;
main := bar; // bar (-> bar) -> qux
END_FUNCTION
";

let res: i32 = compile_and_run(function, &mut MainType::default());
assert_eq!(5, res);
}

#[test]
fn reference_to_variable_referencing_struct() {
let function = r"
TYPE Transaction : STRUCT
id : DINT;
amount : DINT;
message : STRING;
END_STRUCT END_TYPE
FUNCTION main : DINT
VAR
txn : Transaction := (id := 1, amount := 5, message := 'whats up');
refTxn : REFERENCE TO Transaction;
END_VAR
refTxn REF= txn;
main := refTxn.amount;
END_FUNCTION
";

let res: i32 = compile_and_run(function, &mut MainType::default());
assert_eq!(5, res);
}
11 changes: 11 additions & 0 deletions tests/lit/single/pointer/ref_assignment_operator.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
// CHECK: 5
FUNCTION main : DINT
VAR
a : REF_TO DINT;
b : DINT := 5;
END_VAR
a REF= b;

printf('%d$N', a^);
END_FUNCTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
// CHECK: 5
FUNCTION main : DINT
VAR
foo : REFERENCE TO DINT;
bar : REFERENCE TO DINT;
qux : DINT;
END_VAR

foo REF= bar;
bar REF= qux;

bar REF= bar;
qux := 5;

printf('%d$N', bar); // bar (-> bar) -> qux
END_FUNCTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
// CHECK: 5
FUNCTION main : DINT
VAR
foo : REFERENCE TO DINT;
bar : REFERENCE TO DINT;
qux : DINT;
END_VAR

bar REF= qux;
foo REF= bar;
qux := 5;

printf('%d$N', foo); // foo -> bar -> qux
END_FUNCTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
// CHECK: 5
TYPE Transaction : STRUCT
id : DINT;
amount : DINT;
message : STRING;
END_STRUCT END_TYPE

FUNCTION main : DINT
VAR
txn : Transaction := (id := 1, amount := 5, message := 'whats up');
refTxn : REFERENCE TO Transaction;
END_VAR

refTxn REF= txn;
printf('%d$N', refTxn.amount);
END_FUNCTION

0 comments on commit 64b759a

Please sign in to comment.