Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validate Pointer - Numerics assignments if it is no perfect match #516

Merged
merged 2 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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