Skip to content

Commit

Permalink
validate Pointer - Numerics assignments if it is no perfect match (#516)
Browse files Browse the repository at this point in the history
* validate Pointer incl. tests
  • Loading branch information
flavioBachmann committed Jul 14, 2022
1 parent ece0315 commit 151bbc7
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub enum ErrNo {
type__invalid_nature,
type__unknown_nature,
type__unresolved_generic,
type__incompatible_size,

//codegen related
codegen__general,
Expand Down Expand Up @@ -513,6 +514,22 @@ impl Diagnostic {
}
}

pub fn incompatible_type_size(
nature: &str,
size: u32,
error: &str,
location: SourceRange,
) -> Diagnostic {
Diagnostic::SyntaxError {
message: format!(
"The type {} {} is too small to {} Pointer",
nature, size, error
),
range: location,
err_no: ErrNo::type__incompatible_size,
}
}

pub fn link_error(error: &str) -> Diagnostic {
Diagnostic::GeneralError {
err_no: ErrNo::linker__generic_error,
Expand Down
2 changes: 2 additions & 0 deletions src/typesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub type NativeDwordType = u32;
pub type NativeLwordType = u64;
pub type NativeRealType = f32;
pub type NativeLrealType = f64;
pub type NativePointerType = usize;

//TODO should we change this to usize?
pub const U1_SIZE: u32 = 1;
Expand All @@ -39,6 +40,7 @@ pub const LINT_SIZE: u32 = NativeLintType::BITS as u32;
pub const REAL_SIZE: u32 = (size_of::<NativeRealType>() * 8) as u32;
pub const LREAL_SIZE: u32 = (size_of::<NativeLrealType>() * 8) as u32;
pub const DATE_TIME_SIZE: u32 = 64;
pub const POINTER_SIZE: u32 = NativePointerType::BITS as u32;

pub const U1_TYPE: &str = "__U1";
/// used internally for forced casts to u1
Expand Down
30 changes: 28 additions & 2 deletions src/validation/stmt_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use crate::{
resolver::{AnnotationMap, StatementAnnotation},
typesystem::{
DataType, DataTypeInformation, Dimension, BOOL_TYPE, DATE_AND_TIME_TYPE, DATE_TYPE,
DINT_TYPE, INT_TYPE, LINT_TYPE, LREAL_TYPE, SINT_TYPE, STRING_TYPE, TIME_OF_DAY_TYPE,
TIME_TYPE, UDINT_TYPE, UINT_TYPE, ULINT_TYPE, USINT_TYPE, VOID_TYPE, WSTRING_TYPE,
DINT_TYPE, INT_TYPE, LINT_TYPE, LREAL_TYPE, POINTER_SIZE, SINT_TYPE, STRING_TYPE,
TIME_OF_DAY_TYPE, TIME_TYPE, UDINT_TYPE, UINT_TYPE, ULINT_TYPE, USINT_TYPE, VOID_TYPE,
WSTRING_TYPE,
},
Diagnostic,
};
Expand Down Expand Up @@ -137,6 +138,31 @@ impl StatementValidator {
.get_type_or_void(right, context.index)
.get_type_information();

//check if Datatype can hold a Pointer (u64)
if r_effective_type.is_pointer()
&& !l_effective_type.is_pointer()
&& l_effective_type.get_size() < POINTER_SIZE
{
self.diagnostics.push(Diagnostic::incompatible_type_size(
l_effective_type.get_name(),
l_effective_type.get_size(),
"hold a",
statement.get_location(),
));
}
//check if size allocated to Pointer is standart pointer size (u64)
else if l_effective_type.is_pointer()
&& !r_effective_type.is_pointer()
&& r_effective_type.get_size() < POINTER_SIZE
{
self.diagnostics.push(Diagnostic::incompatible_type_size(
r_effective_type.get_name(),
r_effective_type.get_size(),
"to be stored in a",
statement.get_location(),
));
}

// valid assignments -> char := literalString, char := char
// check if we assign to a character variable -> char := ..
if l_effective_type.is_character() {
Expand Down
82 changes: 82 additions & 0 deletions src/validation/tests/statement_validation_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,88 @@
use crate::test_utils::tests::parse_and_validate;
use crate::Diagnostic;

#[test]
fn assign_pointer_to_too_small_type_result_in_an_error() {
//GIVEN assignment statements to DWORD
//WHEN it is validated
let diagnostics: Vec<Diagnostic> = parse_and_validate(
"
PROGRAM FOO
VAR
ptr : POINTER TO INT;
address : DWORD;
END_VAR
address := 16#DEAD_BEEF;
address := ptr; //should throw error as address is too small to store full pointer
END_PROGRAM
",
);

//THEN assignment with different type sizes are reported
assert_eq!(
diagnostics,
vec![Diagnostic::incompatible_type_size(
"DWORD",
32,
"hold a",
(204..218).into()
),]
);
}

#[test]
fn assign_too_small_type_to_pointer_result_in_an_error() {
//GIVEN assignment statements to pointer
//WHEN it is validated
let diagnostics: Vec<Diagnostic> = parse_and_validate(
"
PROGRAM FOO
VAR
ptr : POINTER TO INT;
address : DWORD;
END_VAR
address := 16#DEAD_BEEF;
ptr := address; //should throw error as address is too small to store full pointer
END_PROGRAM
",
);

//THEN assignment with different type sizes are reported
assert_eq!(
diagnostics,
vec![Diagnostic::incompatible_type_size(
"DWORD",
32,
"to be stored in a",
(204..218).into()
),]
);
}

#[test]
fn assign_pointer_to_lword() {
//GIVEN assignment statements to lword
//WHEN it is validated
let diagnostics: Vec<Diagnostic> = parse_and_validate(
"
PROGRAM FOO
VAR
ptr : POINTER TO INT;
address : LWORD;
END_VAR
address := 16#DEAD_BEEF;
address := ptr; //should throw error as address is too small to store full pointer
END_PROGRAM
",
);

//THEN every assignment is valid
assert_eq!(diagnostics, vec![]);
}

#[test]
fn assignment_to_constants_result_in_an_error() {
// GIVEN assignment statements to constants, some to writable variables
Expand Down

0 comments on commit 151bbc7

Please sign in to comment.