diff --git a/book/src/datatypes.md b/book/src/datatypes.md index b1c3d78f517..f1c1bb4474b 100644 --- a/book/src/datatypes.md +++ b/book/src/datatypes.md @@ -87,18 +87,23 @@ Examples: | Type name | Size | Internally stored as | | --------------- | ------ | --------------------------------- | -| TIME | 64 bit | Timespan in nanoseconds | -| TIME\_OF\_DAY | 64 bit | Nanoseconds since Jan 1, 1970 UTC | -| DATE | 64 bit | Nanoseconds since Jan 1, 1970 UTC | -| DATE\_AND\_TIME | 64 bit | Nanoseconds since Jan 1, 1970 UTC | - -Note that RuSTy already treats `TIME`, `TIME_OF_DAY`, `DATE` and `DATE_AND_TIME` as 64 bit numbers. -Therefore the long pendants `LTIME`, `LTOD`, `LDATE` and `LDT` are mere aliases to the original types. +| TIME | 32 bit | Unsigned milliseconds | +| TIME\_OF\_DAY | 32 bit | Unsigned milliseconds since Jan 1, 1970 UTC | +| DATE | 32 bit | Unsigned seconds since Jan 1, 1970 UTC | +| DATE\_AND\_TIME | 32 bit | Unsigned seconds since Jan 1, 1970 UTC | +| LTIME | 64 bit | Nanoseconds | +| LTIME\_OF\_DAY | 64 bit | Nanoseconds since Jan 1, 1970 UTC | +| LDATE | 64 bit | Nanoseconds since Jan 1, 1970 UTC | +| LDATE\_AND\_TIME| 64 bit | Nanoseconds since Jan 1, 1970 UTC | + +RuSTy treats the short date/time family (`TIME`, `TIME_OF_DAY`, `DATE`, `DATE_AND_TIME`) as 32-bit unsigned values. +Short `TIME`/`TOD` use milliseconds, while short `DATE`/`DT` use seconds. +The long family (`LTIME`, `LTOD`, `LDATE`, `LDT`) remains 64-bit nanosecond precision. ### DATE The `DATE` datatype is used to represent a Date in the Gregorian Calendar. -Such a value is stored as an i64 with a precision in nanoseconds and denotes the number of nanoseconds +Such a value is stored as a `u32` with a precision in seconds and denotes the number of seconds that have elapsed since January 1, 1970 UTC not counting leap seconds. DATE literals start with `DATE#` or `D#` followed by a date in the format of `yyyy-mm-dd`. @@ -111,8 +116,8 @@ Examples: ### DATE_AND_TIME The `DATE_AND_TIME` datatype is used to represent a certain point in time in the Gregorian Calendar. -Such a value is stored as an `i64` with a precision in nanoseconds and denotes the -number of nanoseconds that have elapsed since January 1, 1970 UTC not counting leap seconds. +Such a value is stored as a `u32` with a precision in seconds and denotes the +number of seconds that have elapsed since January 1, 1970 UTC not counting leap seconds. DATE_AND_TIME literals start with `DATE_AND_TIME#` or `DT#` followed by a date and time in the format of `yyyy-mm-dd-hh:mm:ss`. @@ -127,27 +132,27 @@ Examples: ### TIME_OF_DAY The `TIME_OF_DAY` datatype is used to represent a specific moment in time in a day. -Such a value is stored as an `i64` value with a precision in nanoseconds and denotes the -number of nanoseconds that have elapsed since January 1, 1970 UTC not counting leap seconds. +Such a value is stored as a `u32` value with a precision in milliseconds and denotes the +number of milliseconds that have elapsed since January 1, 1970 UTC not counting leap seconds. Hence this value is stored as a `DATE_AND_TIME` with the day fixed to 1970-01-01. `TIME_OF_DAY` literals start with `TIME_OF_DAY#` or `TOD#` followed by a time in the format of `hh:mm:ss`. -Note that only the seconeds-segment can have a fraction denoting the milliseconds. +Note that only the seconds-segment can have a fraction denoting the milliseconds. Examples: - `t1 : TIME_OF_DAY := TIME_OF_DAY#14:20:10.25;` -- `t2 : TIME_OF_DAY := TIME_OF_DY#0:00:1;` +- `t2 : TIME_OF_DAY := TIME_OF_DAY#0:00:1;` - `t3 : TIME_OF_DAY := TOD#23:59:59.999;` ### TIME The `TIME` datatype is used to represent a time-span. -A `TIME` value is stored as an `i64` value with a precision in nanoseconds. -TIME literals start with `TIME#` or `T#` followed by the `TIME` segements. +A `TIME` value is stored as a `u32` value with a precision in milliseconds. +TIME literals start with `TIME#` or `T#` followed by the `TIME` segments. -Supported segements are: +Supported segments are: - `d` ... `f64` days - `h` ... `f64` hours @@ -165,6 +170,76 @@ Examples: - `t2 : TIME := T#2d4.2h;` - `t3 : TIME := T#-10s4ms16ns;` +### LDATE + +The `LDATE` datatype is used to represent a Date in the Gregorian Calendar. +Such a value is stored as an `i64` with a precision in nanoseconds and denotes the number of nanoseconds +that have elapsed since January 1, 1970 UTC not counting leap seconds. +LDATE literals start with `LDATE#` or `LD#` followed by a date in the format of `yyyy-mm-dd`. + +Examples: + +- `d1 : LDATE := LDATE#2021-05-02;` +- `d2 : LDATE := LDATE#1-12-24;` +- `d3 : LDATE := LD#2000-1-1;` + +### LDATE_AND_TIME + +The `LDATE_AND_TIME` datatype is used to represent a certain point in time in the Gregorian Calendar. +Such a value is stored as an `i64` with a precision in nanoseconds and denotes the +number of nanoseconds that have elapsed since January 1, 1970 UTC not counting leap seconds. +LDATE_AND_TIME literals start with `LDATE_AND_TIME#` or `LDT#` followed by a date and time in the +format of `yyyy-mm-dd-hh:mm:ss`. + +Note that only the seconds-segment can have a fraction denoting the milliseconds. + +Examples: + +- `d1 : LDATE_AND_TIME := LDATE_AND_TIME#2021-05-02-14:20:10.25;` +- `d2 : LDATE_AND_TIME := LDATE_AND_TIME#1-12-24-00:00:1;` +- `d3 : LDATE_AND_TIME := LDT#1999-12-31-23:59:59.999;` + +### LTIME_OF_DAY + +The `LTIME_OF_DAY` datatype is used to represent a specific moment in time in a day. +Such a value is stored as an `i64` value with a precision in nanoseconds and denotes the +number of nanoseconds that have elapsed since January 1, 1970 UTC not counting leap seconds. +Hence this value is stored as a `LDATE_AND_TIME` with the day fixed to 1970-01-01. +`LTIME_OF_DAY` literals start with `LTIME_OF_DAY#` or `LTOD#` followed by a time in the +format of `hh:mm:ss`. + +Note that only the seconds-segment can have a fraction denoting the milliseconds. + +Examples: + +- `t1 : LTIME_OF_DAY := LTIME_OF_DAY#14:20:10.25;` +- `t2 : LTIME_OF_DAY := LTIME_OF_DAY#0:00:1;` +- `t3 : LTIME_OF_DAY := LTOD#23:59:59.999;` + +### LTIME + +The `LTIME` datatype is used to represent a time-span. +A `LTIME` value is stored as an `i64` value with a precision in nanoseconds. +LTIME literals start with `LTIME#` or `LT#` followed by the `LTIME` segments. + +Supported segments are: + +- `d` ... `f64` days +- `h` ... `f64` hours +- `m` ... `f64`minutes +- `s` ... `f64` seconds +- `ms` ... `f64` milliseconds +- `us` ... `f64` microseconds +- `ns` ... `u32` nanaoseconds + +Note that only the last segment of a `LTIME` literal can have a fraction. + +Examples: + +- `t1 : LTIME := LTIME#2d4h6m8s10ms;` +- `t2 : LTIME := LT#2d4.2h;` +- `t3 : LTIME := LT#-10s4ms16ns;` + ## Other types The `BOOL` type can either be assigned `TRUE` or `FALSE`. diff --git a/book/src/libraries/api_lib_guide.md b/book/src/libraries/api_lib_guide.md index c9b403fd8c0..1ea81d5cad8 100644 --- a/book/src/libraries/api_lib_guide.md +++ b/book/src/libraries/api_lib_guide.md @@ -269,17 +269,17 @@ Below is a table of types and how they can be used from `C` | ULINT | uint64_t | 64 | | | REAL | float_t | 32 | | | LREAL | double_t | 64 | | -| TIME | time_t | 64 | Note that all time and date types are 64 bit | +| TIME | time_t | 32 | Short TIME/TOD types use 32-bit milliseconds | | LTIME | time_t | 64 | | -| DATE | time_t | 64 | | +| DATE | time_t | 32 | Short DATE/DT types use 32-bit seconds | | LDATE | time_t | 64 | | -| DATE_AND_TIME | time_t | 64 | | +| DATE_AND_TIME | time_t | 32 | | | LDATE_AND_TIME | time_t | 64 | | -| DT | time_t | 64 | | +| DT | time_t | 32 | | | LDT | time_t | 64 | | -| TIME_OF_DAY | time_t | 64 | | +| TIME_OF_DAY | time_t | 32 | | | LTIME_OF_DAY | time_t | 64 | | -| TOD | time_t | 64 | | +| TOD | time_t | 32 | | | LTOD | time_t | 64 | | | POINTER TO type | \*type | 64 | The Pointer size is equivalent to `LWORD` and not `DWORD` | | REF_TO type | \*type | 64 | Prefer this type to `POINTER TO` for standard compliance | @@ -345,7 +345,7 @@ pub struct myStruct { ### 2.5 `FUNCTION_BLOCK` initialization -When creating a library with `FUNCTION_BLOCK`s, you can implement initialization logic that runs when an instance is created. +When creating a library with `FUNCTION_BLOCK`s, you can implement initialization logic that runs when an instance is created. For more details on `FB_INIT` in IEC61131-3, refer to the [Program Organization Units (POUs)](../pous.md#function_block-initialization) documentation. @@ -373,7 +373,7 @@ void myFunctionBlock__FB_INIT(myFunctionBlock* fb_instance) { // Initialize members here fb_instance->a = 1; fb_instance->b = 2; - + // ...perform any other needed initialization } ``` diff --git a/compiler/plc_ast/src/literals.rs b/compiler/plc_ast/src/literals.rs index dee7ed6286d..dbd80649c75 100644 --- a/compiler/plc_ast/src/literals.rs +++ b/compiler/plc_ast/src/literals.rs @@ -47,6 +47,7 @@ pub struct Date { year: i32, month: u32, day: u32, + is_long: bool, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -58,6 +59,7 @@ pub struct DateAndTime { min: u32, sec: u32, nano: u32, + is_long: bool, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -66,6 +68,7 @@ pub struct TimeOfDay { min: u32, sec: u32, nano: u32, + is_long: bool, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -78,6 +81,7 @@ pub struct Time { pub micro: f64, pub nano: u32, pub negative: bool, + pub is_long: bool, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -177,6 +181,28 @@ impl Time { pub fn is_negative(&self) -> bool { self.negative } + + pub fn is_long(&self) -> bool { + self.is_long + } +} + +impl Date { + pub fn is_long(&self) -> bool { + self.is_long + } +} + +impl DateAndTime { + pub fn is_long(&self) -> bool { + self.is_long + } +} + +impl TimeOfDay { + pub fn is_long(&self) -> bool { + self.is_long + } } impl Array { @@ -209,7 +235,12 @@ impl AstLiteral { /// Creates a new literal date pub fn new_date(year: i32, month: u32, day: u32) -> Self { - AstLiteral::Date(Date { year, month, day }) + AstLiteral::Date(Date { year, month, day, is_long: false }) + } + + /// Creates a new literal date with explicit width flavor + pub fn new_date_with_long_flag(year: i32, month: u32, day: u32, is_long: bool) -> Self { + AstLiteral::Date(Date { year, month, day, is_long }) } /// Creates a new literal date and time @@ -222,12 +253,30 @@ impl AstLiteral { sec: u32, nano: u32, ) -> Self { - AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano }) + AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano, is_long: false }) + } + + /// Creates a new long literal date and time + pub fn new_long_date_and_time( + year: i32, + month: u32, + day: u32, + hour: u32, + min: u32, + sec: u32, + nano: u32, + ) -> Self { + AstLiteral::DateAndTime(DateAndTime { year, month, day, hour, min, sec, nano, is_long: true }) } /// Creates a new literal time of day pub fn new_time_of_day(hour: u32, min: u32, sec: u32, nano: u32) -> Self { - AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano }) + AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano, is_long: false }) + } + + /// Creates a new literal time of day with explicit width flavor + pub fn new_time_of_day_with_long_flag(hour: u32, min: u32, sec: u32, nano: u32, is_long: bool) -> Self { + AstLiteral::TimeOfDay(TimeOfDay { hour, min, sec, nano, is_long }) } /// Creates a new literal null diff --git a/compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs b/compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs index 8747e339ab0..c5c48d9f7a5 100644 --- a/compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs +++ b/compiler/plc_diagnostics/src/diagnostics/diagnostics_registry.rs @@ -243,6 +243,7 @@ lazy_static! { E139, Error, include_str!("./error_codes/E139.md"), // Linker invocation failed (spawn / cmdline) E140, Error, include_str!("./error_codes/E140.md"), // ':=' used for an output parameter E141, Error, include_str!("./error_codes/E141.md"), // Member access on a non-auto-deref pointer base + E142, Warning, include_str!("./error_codes/E142.md"), // Temporal literal overflow or underflow ); } diff --git a/compiler/plc_diagnostics/src/diagnostics/error_codes/E142.md b/compiler/plc_diagnostics/src/diagnostics/error_codes/E142.md new file mode 100644 index 00000000000..b9562027b37 --- /dev/null +++ b/compiler/plc_diagnostics/src/diagnostics/error_codes/E142.md @@ -0,0 +1,10 @@ +# E142 + +Temporal literal overflow or underflow. + +This warning is emitted when a temporal literal cannot be represented safely. + +Covered temporal literals include DATE, DT, TOD, TIME and their long variants. + +For short temporal types (DATE/DT/TOD/TIME), values outside the 32-bit runtime storage domain trigger this warning. +For long temporal types, out-of-range literal encodings also trigger this warning. diff --git a/libs/stdlib/iec61131-st/date_time_conversion.st b/libs/stdlib/iec61131-st/date_time_conversion.st index 91bae5d3dcc..d7d047d1b92 100644 --- a/libs/stdlib/iec61131-st/date_time_conversion.st +++ b/libs/stdlib/iec61131-st/date_time_conversion.st @@ -1,6 +1,6 @@ (******************** * -* Converts DT/LDT to DATE +* Converts DT to DATE * *********************) {external} @@ -12,7 +12,19 @@ END_FUNCTION (******************** * -* Converts DT/LDT to TOD/LTOD +* Converts LDT to LDATE +* +*********************) +{external} +FUNCTION LDATE_AND_TIME_TO_LDATE : LDATE +VAR_INPUT + in : LDT; +END_VAR +END_FUNCTION + +(******************** +* +* Converts DT to TOD * *********************) {external} @@ -22,16 +34,28 @@ VAR_INPUT END_VAR END_FUNCTION +(******************** +* +* Converts LDT to LTOD +* +*********************) +{external} +FUNCTION LDATE_AND_TIME_TO_LTIME_OF_DAY : LTOD +VAR_INPUT + in : LDT; +END_VAR +END_FUNCTION + (******************** * * Converts LTIME to TIME * *********************) +{external} FUNCTION LTIME_TO_TIME : TIME VAR_INPUT in : LTIME; END_VAR - LTIME_TO_TIME := in; END_FUNCTION (******************** @@ -39,11 +63,11 @@ END_FUNCTION * Converts TIME to LTIME * *********************) +{external} FUNCTION TIME_TO_LTIME : LTIME VAR_INPUT in : TIME; END_VAR - TIME_TO_LTIME := in; END_FUNCTION (******************** @@ -51,11 +75,11 @@ END_FUNCTION * Converts LDT to DT * *********************) +{external} FUNCTION LDT_TO_DT : DT VAR_INPUT in : LDT; END_VAR - LDT_TO_DT := in; END_FUNCTION (******************** @@ -63,11 +87,11 @@ END_FUNCTION * Converts LDT to DATE * *********************) +{external} FUNCTION LDT_TO_DATE : DATE VAR_INPUT in : LDT; END_VAR - LDT_TO_DATE := DATE_AND_TIME_TO_DATE(in); END_FUNCTION (******************** @@ -75,11 +99,11 @@ END_FUNCTION * Converts LDT to LTOD * *********************) +{external} FUNCTION LDT_TO_LTOD : LTOD VAR_INPUT in : LDT; END_VAR - LDT_TO_LTOD := DATE_AND_TIME_TO_TIME_OF_DAY(in); END_FUNCTION (******************** @@ -87,11 +111,11 @@ END_FUNCTION * Converts LDT to TOD * *********************) +{external} FUNCTION LDT_TO_TOD : TOD VAR_INPUT in : LDT; END_VAR - LDT_TO_TOD := DATE_AND_TIME_TO_TIME_OF_DAY(in); END_FUNCTION (******************** @@ -99,11 +123,11 @@ END_FUNCTION * Converts DT to LDT * *********************) +{external} FUNCTION DT_TO_LDT : LDT VAR_INPUT in : DT; END_VAR - DT_TO_LDT := in; END_FUNCTION (******************** @@ -111,11 +135,23 @@ END_FUNCTION * Converts DT to DATE * *********************) +{external} FUNCTION DT_TO_DATE : DATE VAR_INPUT in : DT; END_VAR - DT_TO_DATE := DATE_AND_TIME_TO_DATE(in); +END_FUNCTION + +(******************** +* +* Converts DT to LDATE +* +*********************) +{external} +FUNCTION DT_TO_LDATE : LDATE +VAR_INPUT + in : DT; +END_VAR END_FUNCTION (******************** @@ -123,11 +159,11 @@ END_FUNCTION * Converts DT to LTOD * *********************) +{external} FUNCTION DT_TO_LTOD : LTOD VAR_INPUT in : DT; END_VAR - DT_TO_LTOD := DATE_AND_TIME_TO_TIME_OF_DAY(in); END_FUNCTION (******************** @@ -135,11 +171,11 @@ END_FUNCTION * Converts DT to TOD * *********************) +{external} FUNCTION DT_TO_TOD : TOD VAR_INPUT in : DT; END_VAR - DT_TO_TOD := DATE_AND_TIME_TO_TIME_OF_DAY(in); END_FUNCTION (******************** @@ -147,11 +183,11 @@ END_FUNCTION * Converts LTOD to TOD * *********************) +{external} FUNCTION LTOD_TO_TOD : TOD VAR_INPUT in : LTOD; END_VAR - LTOD_TO_TOD := in; END_FUNCTION (******************** @@ -159,9 +195,9 @@ END_FUNCTION * Converts TOD to LTOD * *********************) +{external} FUNCTION TOD_TO_LTOD : LTOD VAR_INPUT in : TOD; END_VAR - TOD_TO_LTOD := in; END_FUNCTION diff --git a/libs/stdlib/iec61131-st/date_time_extra_functions.st b/libs/stdlib/iec61131-st/date_time_extra_functions.st index 42d630308ac..850cc68339a 100644 --- a/libs/stdlib/iec61131-st/date_time_extra_functions.st +++ b/libs/stdlib/iec61131-st/date_time_extra_functions.st @@ -16,12 +16,12 @@ END_FUNCTION * Concatenates DATE and LTOD to DT * *********************) -FUNCTION CONCAT_DATE_LTOD : DT +{external} +FUNCTION CONCAT_DATE_LTOD : LDT VAR_INPUT date_input : DATE; tod_input : LTOD; END_VAR - CONCAT_DATE_LTOD := CONCAT_DATE_TOD(date_input, tod_input); END_FUNCTION (******************** @@ -68,6 +68,7 @@ END_VAR END_FUNCTION (* Specialized implementation of CONCAT_LTOD for SINT *) +{external} FUNCTION CONCAT_LTOD__SINT : LTOD VAR_INPUT hour : SINT; @@ -75,10 +76,10 @@ VAR_INPUT second : SINT; millisecond : SINT; END_VAR - CONCAT_LTOD__SINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for USINT *) +{external} FUNCTION CONCAT_LTOD__USINT : LTOD VAR_INPUT hour : USINT; @@ -86,10 +87,10 @@ VAR_INPUT second : USINT; millisecond : USINT; END_VAR - CONCAT_LTOD__USINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for INT *) +{external} FUNCTION CONCAT_LTOD__INT : LTOD VAR_INPUT hour : INT; @@ -97,10 +98,10 @@ VAR_INPUT second : INT; millisecond : INT; END_VAR - CONCAT_LTOD__INT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for UINT *) +{external} FUNCTION CONCAT_LTOD__UINT : LTOD VAR_INPUT hour : UINT; @@ -108,10 +109,10 @@ VAR_INPUT second : UINT; millisecond : UINT; END_VAR - CONCAT_LTOD__UINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for DINT *) +{external} FUNCTION CONCAT_LTOD__DINT : LTOD VAR_INPUT hour : DINT; @@ -119,10 +120,10 @@ VAR_INPUT second : DINT; millisecond : DINT; END_VAR - CONCAT_LTOD__DINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for UDINT *) +{external} FUNCTION CONCAT_LTOD__UDINT : LTOD VAR_INPUT hour : UDINT; @@ -130,10 +131,10 @@ VAR_INPUT second : UDINT; millisecond : UDINT; END_VAR - CONCAT_LTOD__UDINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for LINT *) +{external} FUNCTION CONCAT_LTOD__LINT : LTOD VAR_INPUT hour : LINT; @@ -141,10 +142,10 @@ VAR_INPUT second : LINT; millisecond : LINT; END_VAR - CONCAT_LTOD__LINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of CONCAT_LTOD for ULINT *) +{external} FUNCTION CONCAT_LTOD__ULINT : LTOD VAR_INPUT hour : ULINT; @@ -152,7 +153,6 @@ VAR_INPUT second : ULINT; millisecond : ULINT; END_VAR - CONCAT_LTOD__ULINT := CONCAT_TOD(hour, minute, second, millisecond); END_FUNCTION (******************** @@ -274,6 +274,7 @@ END_VAR END_FUNCTION (* Specialized implementation of CONCAT_LDT for INT *) +{external} FUNCTION CONCAT_LDT__INT : LDT VAR_INPUT year : INT; @@ -284,10 +285,10 @@ VAR_INPUT second : INT; millisecond : INT; END_VAR - CONCAT_LDT__INT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (* Specialized implementation of CONCAT_LDT for UINT *) +{external} FUNCTION CONCAT_LDT__UINT : LDT VAR_INPUT year : UINT; @@ -298,10 +299,10 @@ VAR_INPUT second : UINT; millisecond : UINT; END_VAR - CONCAT_LDT__UINT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (* Specialized implementation of CONCAT_LDT for DINT *) +{external} FUNCTION CONCAT_LDT__DINT : LDT VAR_INPUT year : DINT; @@ -312,10 +313,10 @@ VAR_INPUT second : DINT; millisecond : DINT; END_VAR - CONCAT_LDT__DINT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (* Specialized implementation of CONCAT_LDT for UDINT *) +{external} FUNCTION CONCAT_LDT__UDINT : LDT VAR_INPUT year : UDINT; @@ -326,10 +327,10 @@ VAR_INPUT second : UDINT; millisecond : UDINT; END_VAR - CONCAT_LDT__UDINT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (* Specialized implementation of CONCAT_LDT for LINT *) +{external} FUNCTION CONCAT_LDT__LINT : LDT VAR_INPUT year : LINT; @@ -340,10 +341,10 @@ VAR_INPUT second : LINT; millisecond : LINT; END_VAR - CONCAT_LDT__LINT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (* Specialized implementation of CONCAT_LDT for ULINT *) +{external} FUNCTION CONCAT_LDT__ULINT : LDT VAR_INPUT year : ULINT; @@ -354,7 +355,6 @@ VAR_INPUT second : ULINT; millisecond : ULINT; END_VAR - CONCAT_LDT__ULINT := CONCAT_DATE_LTOD(CONCAT_DATE(year, month, day), CONCAT_LTOD(hour, minute, second, millisecond)); END_FUNCTION (******************** @@ -570,6 +570,7 @@ END_VAR END_FUNCTION (* Specialized implementation of SPLIT_LTOD for INT *) +{external} FUNCTION SPLIT_LTOD__INT : INT VAR_INPUT in : LTOD; @@ -580,10 +581,10 @@ VAR_OUTPUT second : INT; millisecond : INT; END_VAR - SPLIT_LTOD__INT := SPLIT_TOD__INT(in, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LTOD for UINT *) +{external} FUNCTION SPLIT_LTOD__UINT : INT VAR_INPUT in : LTOD; @@ -594,10 +595,10 @@ VAR_OUTPUT second : UINT; millisecond : UINT; END_VAR - SPLIT_LTOD__UINT := SPLIT_TOD__UINT(in, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LTOD for DINT *) +{external} FUNCTION SPLIT_LTOD__DINT : INT VAR_INPUT in : LTOD; @@ -608,10 +609,10 @@ VAR_OUTPUT second : DINT; millisecond : DINT; END_VAR - SPLIT_LTOD__DINT := SPLIT_TOD__DINT(in, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LTOD for UDINT *) +{external} FUNCTION SPLIT_LTOD__UDINT : INT VAR_INPUT in : LTOD; @@ -622,10 +623,10 @@ VAR_OUTPUT second : UDINT; millisecond : UDINT; END_VAR - SPLIT_LTOD__UDINT := SPLIT_TOD__UDINT(in, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LTOD for LINT *) +{external} FUNCTION SPLIT_LTOD__LINT : INT VAR_INPUT in : LTOD; @@ -636,10 +637,10 @@ VAR_OUTPUT second : LINT; millisecond : LINT; END_VAR - SPLIT_LTOD__LINT := SPLIT_TOD__LINT(in, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LTOD for ULINT *) +{external} FUNCTION SPLIT_LTOD__ULINT : INT VAR_INPUT in : LTOD; @@ -650,7 +651,6 @@ VAR_OUTPUT second : ULINT; millisecond : ULINT; END_VAR - SPLIT_LTOD__ULINT := SPLIT_TOD__ULINT(in, hour, minute, second, millisecond); END_FUNCTION (******************** @@ -810,7 +810,6 @@ VAR_OUTPUT second : INT; millisecond : INT; END_VAR - SPLIT_LDT__INT := SPLIT_DT__INT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LDT for UINT *) @@ -828,7 +827,6 @@ VAR_OUTPUT second : UINT; millisecond : UINT; END_VAR - SPLIT_LDT__UINT := SPLIT_DT__UINT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LDT for DINT *) @@ -846,7 +844,6 @@ VAR_OUTPUT second : DINT; millisecond : DINT; END_VAR - SPLIT_LDT__DINT := SPLIT_DT__DINT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LDT for UDINT *) @@ -864,7 +861,6 @@ VAR_OUTPUT second : UDINT; millisecond : UDINT; END_VAR - SPLIT_LDT__UDINT := SPLIT_DT__UDINT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LDT for LINT *) @@ -882,7 +878,6 @@ VAR_OUTPUT second : LINT; millisecond : LINT; END_VAR - SPLIT_LDT__LINT := SPLIT_DT__LINT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (* Specialized implementation of SPLIT_LDT for ULINT *) @@ -900,7 +895,6 @@ VAR_OUTPUT second : ULINT; millisecond : ULINT; END_VAR - SPLIT_LDT__ULINT := SPLIT_DT__ULINT(in, year, month, day, hour, minute, second, millisecond); END_FUNCTION (******************** diff --git a/libs/stdlib/iec61131-st/date_time_numeric_functions.st b/libs/stdlib/iec61131-st/date_time_numeric_functions.st index 2a7388d3d43..80010cff201 100644 --- a/libs/stdlib/iec61131-st/date_time_numeric_functions.st +++ b/libs/stdlib/iec61131-st/date_time_numeric_functions.st @@ -25,12 +25,12 @@ END_FUNCTION * This operator returns the value of adding up two LTIME operands. * *********************) +{external} FUNCTION ADD_LTIME: LTIME VAR_INPUT IN1: LTIME; IN2: LTIME; END_VAR - ADD_LTIME := ADD_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of ADD for TOD *) @@ -62,12 +62,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION ADD_LTOD_LTIME: LTOD VAR_INPUT IN1: LTOD; IN2: LTIME; END_VAR - ADD_LTOD_LTIME := ADD_TOD_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of ADD for DT *) @@ -99,12 +99,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION ADD_LDT_LTIME: LDT VAR_INPUT IN1: LDT; IN2: LTIME; END_VAR - ADD_LDT_LTIME := ADD_DT_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for TIME *) @@ -134,12 +134,12 @@ END_FUNCTION * This operator produces the subtraction of two LTIME operands * *********************) +{external} FUNCTION SUB_LTIME: LTIME VAR_INPUT IN1: LTIME; IN2: LTIME; END_VAR - SUB_LTIME := SUB_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for DATE *) @@ -171,12 +171,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION SUB_LDATE_LDATE: LTIME VAR_INPUT IN1: LDATE; IN2: LDATE; END_VAR - SUB_LDATE_LDATE := SUB_DATE_DATE(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for TOD and TIME *) @@ -208,12 +208,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION SUB_LTOD_LTIME: LTOD VAR_INPUT IN1: LTOD; IN2: LTIME; END_VAR - SUB_LTOD_LTIME := SUB_TOD_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for TOD *) @@ -245,12 +245,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION SUB_LTOD_LTOD: LTIME VAR_INPUT IN1: LTOD; IN2: LTOD; END_VAR - SUB_LTOD_LTOD := SUB_TOD_TOD(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for DT and TIME *) @@ -282,12 +282,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION SUB_LDT_LTIME: LDT VAR_INPUT IN1: LDT; IN2: LTIME; END_VAR - SUB_LDT_LTIME := SUB_DT_TIME(IN1, IN2); END_FUNCTION (* Specialized implementation of SUB for DT *) @@ -319,12 +319,12 @@ END_FUNCTION * Panic on overflow * *********************) +{external} FUNCTION SUB_LDT_LDT: LTIME VAR_INPUT IN1: LDT; IN2: LDT; END_VAR - SUB_LDT_LDT := SUB_DT_DT(IN1, IN2); END_FUNCTION (******************** diff --git a/libs/stdlib/iec61131-st/extra_functions.st b/libs/stdlib/iec61131-st/extra_functions.st index a6f4b6fcede..94358932b40 100644 --- a/libs/stdlib/iec61131-st/extra_functions.st +++ b/libs/stdlib/iec61131-st/extra_functions.st @@ -103,27 +103,17 @@ END_FUNCTION * Converts DT to STRING. * ******************************************************************************) +{external} FUNCTION DT_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : DT; END_VAR - DT_TO_STRING_EXT(IN, DT_TO_STRING); END_FUNCTION +{external} FUNCTION LDT_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : LDT; -END_VAR - DT_TO_STRING_EXT(IN, LDT_TO_STRING); -END_FUNCTION - -{external} -FUNCTION DT_TO_STRING_EXT : DINT -VAR_INPUT - IN : DT; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; END_VAR END_FUNCTION @@ -151,27 +141,17 @@ END_FUNCTION * Converts TIME to STRING. * ******************************************************************************) +{external} FUNCTION TIME_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : TIME; END_VAR - TIME_TO_STRING_EXT(IN, TIME_TO_STRING); -END_FUNCTION - -FUNCTION LTIME_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : TIME; -END_VAR - TIME_TO_STRING_EXT(IN, LTIME_TO_STRING); END_FUNCTION {external} -FUNCTION TIME_TO_STRING_EXT : DINT +FUNCTION LTIME_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : TIME; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LTIME; END_VAR END_FUNCTION @@ -189,9 +169,9 @@ END_FUNCTION FUNCTION LTIME_TO_WSTRING : WSTRING[__STRING_LENGTH] VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR - STRING_TO_WSTRING_EXT(TIME_TO_STRING(IN), LTIME_TO_WSTRING); + STRING_TO_WSTRING_EXT(LTIME_TO_STRING(IN), LTIME_TO_WSTRING); END_FUNCTION (****************************************************************************** @@ -199,27 +179,17 @@ END_FUNCTION * Converts DATE to STRING. * ******************************************************************************) +{external} FUNCTION DATE_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : DATE; END_VAR - DATE_TO_STRING_EXT(IN, DATE_TO_STRING); -END_FUNCTION - -FUNCTION LDATE_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : DATE; -END_VAR - DATE_TO_STRING_EXT(IN, LDATE_TO_STRING); END_FUNCTION {external} -FUNCTION DATE_TO_STRING_EXT : DINT +FUNCTION LDATE_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : DATE; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LDATE; END_VAR END_FUNCTION @@ -237,9 +207,9 @@ END_FUNCTION FUNCTION LDATE_TO_WSTRING : WSTRING[__STRING_LENGTH] VAR_INPUT - IN : DATE; + IN : LDATE; END_VAR - STRING_TO_WSTRING_EXT(DATE_TO_STRING(IN), LDATE_TO_WSTRING); + STRING_TO_WSTRING_EXT(LDATE_TO_STRING(IN), LDATE_TO_WSTRING); END_FUNCTION (****************************************************************************** @@ -247,27 +217,17 @@ END_FUNCTION * Converts TOD to STRING. * ******************************************************************************) +{external} FUNCTION TOD_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : TOD; END_VAR - TOD_TO_STRING_EXT(IN, TOD_TO_STRING); -END_FUNCTION - -FUNCTION LTOD_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : TOD; -END_VAR - TOD_TO_STRING_EXT(IN, LTOD_TO_STRING); END_FUNCTION {external} -FUNCTION TOD_TO_STRING_EXT : DINT +FUNCTION LTOD_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : TOD; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LTOD; END_VAR END_FUNCTION @@ -285,9 +245,9 @@ END_FUNCTION FUNCTION LTOD_TO_WSTRING : WSTRING[__STRING_LENGTH] VAR_INPUT - IN : TOD; + IN : LTOD; END_VAR - STRING_TO_WSTRING_EXT(TOD_TO_STRING(IN), LTOD_TO_WSTRING); + STRING_TO_WSTRING_EXT(LTOD_TO_STRING(IN), LTOD_TO_WSTRING); END_FUNCTION (****************************************************************************** @@ -412,7 +372,7 @@ END_FUNCTION FUNCTION LTOD_TO_LWORD : LWORD VAR_INPUT - IN : TOD; + IN : LTOD; END_VAR LTOD_TO_LWORD := IN; END_FUNCTION @@ -450,7 +410,7 @@ END_FUNCTION FUNCTION LDATE_TO_LWORD : LWORD VAR_INPUT - IN : DATE; + IN : LDATE; END_VAR LDATE_TO_LWORD := IN; END_FUNCTION @@ -469,7 +429,7 @@ END_FUNCTION FUNCTION LTIME_TO_LWORD : LWORD VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR LTIME_TO_LWORD := IN; END_FUNCTION @@ -516,7 +476,7 @@ END_FUNCTION FUNCTION LTIME_TO_LINT : LINT VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR LTIME_TO_LINT := IN; END_FUNCTION @@ -535,7 +495,7 @@ END_FUNCTION FUNCTION LTOD_TO_LINT : LINT VAR_INPUT - IN : TOD; + IN : LTOD; END_VAR LTOD_TO_LINT := IN; END_FUNCTION @@ -573,7 +533,7 @@ END_FUNCTION FUNCTION LDATE_TO_LINT : LINT VAR_INPUT - IN : DATE; + IN : LDATE; END_VAR LDATE_TO_LINT := IN; END_FUNCTION @@ -611,7 +571,7 @@ END_FUNCTION FUNCTION LTIME_TO_ULINT : ULINT VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR LTIME_TO_ULINT := IN; END_FUNCTION @@ -630,7 +590,7 @@ END_FUNCTION FUNCTION LDATE_TO_ULINT : ULINT VAR_INPUT - IN : DATE; + IN : LDATE; END_VAR LDATE_TO_ULINT := IN; END_FUNCTION @@ -649,7 +609,7 @@ END_FUNCTION FUNCTION LTOD_TO_ULINT : ULINT VAR_INPUT - IN : TOD; + IN : LTOD; END_VAR LTOD_TO_ULINT := IN; END_FUNCTION @@ -753,7 +713,7 @@ END_FUNCTION FUNCTION LTIME_TO_LREAL : LREAL VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR LTIME_TO_LREAL := IN; END_FUNCTION @@ -771,7 +731,7 @@ END_VAR LREAL_TO_TIME := ROUND(IN); END_FUNCTION -FUNCTION LREAL_TO_LTIME : TIME +FUNCTION LREAL_TO_LTIME : LTIME VAR_INPUT IN : LREAL; END_VAR @@ -790,7 +750,7 @@ END_VAR LWORD_TO_DATE := IN; END_FUNCTION -FUNCTION LWORD_TO_LDATE : DATE +FUNCTION LWORD_TO_LDATE : LDATE VAR_INPUT IN : LWORD; END_VAR @@ -809,7 +769,7 @@ END_VAR LWORD_TO_DT := IN; END_FUNCTION -FUNCTION LWORD_TO_LDT : DT +FUNCTION LWORD_TO_LDT : LDT VAR_INPUT IN : LWORD; END_VAR @@ -828,7 +788,7 @@ END_VAR LWORD_TO_TOD := IN; END_FUNCTION -FUNCTION LWORD_TO_LTOD : TOD +FUNCTION LWORD_TO_LTOD : LTOD VAR_INPUT IN : LWORD; END_VAR @@ -847,7 +807,7 @@ END_VAR LWORD_TO_TIME := IN; END_FUNCTION -FUNCTION LWORD_TO_LTIME : TIME +FUNCTION LWORD_TO_LTIME : LTIME VAR_INPUT IN : LWORD; END_VAR @@ -866,7 +826,7 @@ END_VAR ULINT_TO_DATE := IN; END_FUNCTION -FUNCTION ULINT_TO_LDATE : DATE +FUNCTION ULINT_TO_LDATE : LDATE VAR_INPUT IN : ULINT; END_VAR @@ -885,7 +845,7 @@ END_VAR ULINT_TO_DT := IN; END_FUNCTION -FUNCTION ULINT_TO_LDT : DT +FUNCTION ULINT_TO_LDT : LDT VAR_INPUT IN : ULINT; END_VAR @@ -904,7 +864,7 @@ END_VAR ULINT_TO_TOD := IN; END_FUNCTION -FUNCTION ULINT_TO_LTOD : TOD +FUNCTION ULINT_TO_LTOD : LTOD VAR_INPUT IN : ULINT; END_VAR @@ -942,7 +902,7 @@ END_VAR LINT_TO_TIME := IN; END_FUNCTION -FUNCTION LINT_TO_LTIME : TIME +FUNCTION LINT_TO_LTIME : LTIME VAR_INPUT IN : LINT; END_VAR @@ -961,7 +921,7 @@ END_VAR LINT_TO_TOD := IN; END_FUNCTION -FUNCTION LINT_TO_LTOD : TOD +FUNCTION LINT_TO_LTOD : LTOD VAR_INPUT IN : LINT; END_VAR diff --git a/libs/stdlib/iec61131-st/timers.st b/libs/stdlib/iec61131-st/timers.st index cf11504daf8..b752aa6b721 100644 --- a/libs/stdlib/iec61131-st/timers.st +++ b/libs/stdlib/iec61131-st/timers.st @@ -66,7 +66,7 @@ Return: Output variables are used for return. FUNCTION_BLOCK TP_LTIME VAR_INPUT IN : BOOL; - PT : TIME; + PT : LTIME; END_VAR VAR_OUTPUT Q : BOOL; @@ -151,10 +151,10 @@ VAR_INPUT END_VAR VAR_OUTPUT Q: BOOL; - ET: TIME; + ET: LTIME; END_VAR VAR - __signal__ : BOOL; (* Value representing the internal signal *) + __signal__ : BOOL; (* Value representing the internal signal *) __is_running__: BOOL; (* Internal flag to track timer on/off state *) __BUFFER__ : ARRAY[1..24] OF BYTE; (* Buffer used for internal implementation *) END_VAR diff --git a/libs/stdlib/iec61131-st/to_date_time.st b/libs/stdlib/iec61131-st/to_date_time.st index 179f78ae28e..7422e9ed37e 100644 --- a/libs/stdlib/iec61131-st/to_date_time.st +++ b/libs/stdlib/iec61131-st/to_date_time.st @@ -30,7 +30,7 @@ END_FUNCTION FUNCTION TO_LTIME__LTIME : LTIME VAR_INPUT - in : T; + in : LTIME; END_VAR TO_LTIME__LTIME := in; @@ -38,7 +38,7 @@ END_FUNCTION FUNCTION TO_LTIME__TIME : LTIME VAR_INPUT - in : LTIME; + in : TIME; END_VAR TO_LTIME__TIME := TIME_TO_LTIME(in); @@ -53,11 +53,19 @@ FUNCTION TO_DT : DT END_FUNCTION FUNCTION TO_DT__DATE_AND_TIME : DT + VAR_INPUT + in : DT; + END_VAR + + TO_DT__DATE_AND_TIME := in; +END_FUNCTION + +FUNCTION TO_DT__LDATE_AND_TIME : DT VAR_INPUT in : LDT; END_VAR - TO_DT__DATE_AND_TIME := LDT_TO_DT(in); + TO_DT__LDATE_AND_TIME := LDT_TO_DT(in); END_FUNCTION // ----------------------------------------------------------------------------------------------------------- @@ -69,27 +77,43 @@ FUNCTION TO_DATE : DATE END_FUNCTION FUNCTION TO_DATE__DATE_AND_TIME : DATE + VAR_INPUT + in : DT; + END_VAR + + TO_DATE__DATE_AND_TIME := DT_TO_DATE(in); +END_FUNCTION + +FUNCTION TO_DATE__LDATE_AND_TIME : DATE VAR_INPUT in : LDT; END_VAR - TO_DATE__DATE_AND_TIME := LDT_TO_DATE(in); + TO_DATE__LDATE_AND_TIME := LDT_TO_DATE(in); END_FUNCTION // ----------------------------------------------------------------------------------------------------------- -FUNCTION TO_LDATE : DATE +FUNCTION TO_LDATE : LDATE VAR_INPUT in : T; END_VAR END_FUNCTION -FUNCTION TO_LDATE__DATE_AND_TIME : DATE +FUNCTION TO_LDATE__DATE_AND_TIME : LDATE + VAR_INPUT + in : DT; + END_VAR + + TO_LDATE__DATE_AND_TIME := DT_TO_LDATE(in); +END_FUNCTION + +FUNCTION TO_LDATE__LDATE_AND_TIME : LDATE VAR_INPUT in : LDT; END_VAR - TO_LDATE__DATE_AND_TIME := LDT_TO_DATE(in); + TO_LDATE__LDATE_AND_TIME := LDATE_AND_TIME_TO_LDATE(in); END_FUNCTION // ----------------------------------------------------------------------------------------------------------- @@ -102,18 +126,34 @@ END_FUNCTION FUNCTION TO_TOD__DATE_AND_TIME : TOD VAR_INPUT - in : LDT; + in : DT; END_VAR TO_TOD__DATE_AND_TIME := DT_TO_TOD(in); END_FUNCTION +FUNCTION TO_TOD__LDATE_AND_TIME : TOD + VAR_INPUT + in : LDT; + END_VAR + + TO_TOD__LDATE_AND_TIME := LDT_TO_TOD(in); +END_FUNCTION + FUNCTION TO_TOD__TIME_OF_DAY : TOD + VAR_INPUT + in : TOD; + END_VAR + + TO_TOD__TIME_OF_DAY := in; +END_FUNCTION + +FUNCTION TO_TOD__LTIME_OF_DAY : TOD VAR_INPUT in : LTOD; END_VAR - TO_TOD__TIME_OF_DAY := LTOD_TO_TOD(in); + TO_TOD__LTIME_OF_DAY := TO_TOD__TIME_OF_DAY(in); END_FUNCTION // ----------------------------------------------------------------------------------------------------------- @@ -125,11 +165,19 @@ FUNCTION TO_LTOD : LTOD END_FUNCTION FUNCTION TO_LTOD__DATE_AND_TIME : LTOD + VAR_INPUT + in : DT; + END_VAR + + TO_LTOD__DATE_AND_TIME := DT_TO_LTOD(in); +END_FUNCTION + +FUNCTION TO_LTOD__LDATE_AND_TIME : LTOD VAR_INPUT in : LDT; END_VAR - TO_LTOD__DATE_AND_TIME := LDT_TO_LTOD(in); + TO_LTOD__LDATE_AND_TIME := LDT_TO_LTOD(in); END_FUNCTION FUNCTION TO_LTOD__TIME_OF_DAY : LTOD @@ -140,6 +188,14 @@ FUNCTION TO_LTOD__TIME_OF_DAY : LTOD TO_LTOD__TIME_OF_DAY := TOD_TO_LTOD(in); END_FUNCTION +FUNCTION TO_LTOD__LTIME_OF_DAY : LTOD + VAR_INPUT + in : LTOD; + END_VAR + + TO_LTOD__LTIME_OF_DAY := in; +END_FUNCTION + // ----------------------------------------------------------------------------------------------------------- FUNCTION TO_LDT : LDT @@ -154,4 +210,12 @@ FUNCTION TO_LDT__DATE_AND_TIME : LDT END_VAR TO_LDT__DATE_AND_TIME := DT_TO_LDT(in); -END_FUNCTION \ No newline at end of file +END_FUNCTION + +FUNCTION TO_LDT__LDATE_AND_TIME : LDT + VAR_INPUT + in : LDT; + END_VAR + + TO_LDT__LDATE_AND_TIME := in; +END_FUNCTION diff --git a/libs/stdlib/src/date_time_conversion.rs b/libs/stdlib/src/date_time_conversion.rs index bf9d735a539..d5367b6fcd9 100644 --- a/libs/stdlib/src/date_time_conversion.rs +++ b/libs/stdlib/src/date_time_conversion.rs @@ -1,11 +1,34 @@ use chrono::{TimeZone, Timelike}; +const NANOS_PER_MILLISECOND: i64 = 1_000 * 1_000; +const NANOS_PER_SECOND: i64 = 1_000 * 1_000 * 1_000; +const SECONDS_PER_DAY: u32 = 60 * 60 * 24; + +/// . +/// Converts DT to DATE +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DATE_AND_TIME_TO_DATE(input: u32) -> u32 { + let input_seconds = input as i64; + let date_time = chrono::Utc.timestamp_opt(input_seconds, 0).single().expect("Out of range DT value"); + + let midnight_seconds = date_time + .date_naive() + .and_hms_opt(0, 0, 0) + .expect("Cannot create date time from date") + .and_utc() + .timestamp(); + + midnight_seconds as u32 +} + /// . -/// Converts DT/LDT to DATE +/// Converts LDT to LDATE /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn DATE_AND_TIME_TO_DATE(input: i64) -> i64 { +pub extern "C" fn LDATE_AND_TIME_TO_LDATE(input: i64) -> i64 { let date_time = chrono::Utc.timestamp_nanos(input); let new_date_time = @@ -15,11 +38,28 @@ pub extern "C" fn DATE_AND_TIME_TO_DATE(input: i64) -> i64 { } /// . -/// Converts DT/LDT to TOD/LTOD +/// Converts DT to TOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DATE_AND_TIME_TO_TIME_OF_DAY(input: u32) -> u32 { + let input_seconds = input as i64; + let date_time = chrono::Utc.timestamp_opt(input_seconds, 0).single().expect("Out of range DT value"); + + let midnight = chrono::NaiveDate::from_ymd_opt(1970, 1, 1) + .and_then(|date| date.and_hms_opt(date_time.hour(), date_time.minute(), date_time.second())) + .expect("Cannot create date time from given parameters") + .and_utc(); + + midnight.timestamp_millis() as u32 +} + +/// . +/// Converts LDT to LTOD /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn DATE_AND_TIME_TO_TIME_OF_DAY(input: i64) -> i64 { +pub extern "C" fn LDATE_AND_TIME_TO_LTIME_OF_DAY(input: i64) -> i64 { let date_time = chrono::Utc.timestamp_nanos(input); let hour = date_time.hour(); let min = date_time.minute(); @@ -32,3 +72,120 @@ pub extern "C" fn DATE_AND_TIME_TO_TIME_OF_DAY(input: i64) -> i64 { new_date_time.and_utc().timestamp_nanos_opt().expect("Out of range, cannot create TOD") } + +/// . +/// Converts LTIME to TIME +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LTIME_TO_TIME(input: i64) -> u32 { + (input / NANOS_PER_MILLISECOND) as u32 +} + +/// . +/// Converts TIME to LTIME +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn TIME_TO_LTIME(input: u32) -> i64 { + (input as i64) * NANOS_PER_MILLISECOND +} + +/// . +/// Converts LDT to DT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LDT_TO_DT(input: i64) -> u32 { + (input / NANOS_PER_SECOND) as u32 +} + +/// . +/// Converts LDT to DATE +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LDT_TO_DATE(input: i64) -> u32 { + (LDATE_AND_TIME_TO_LDATE(input) / NANOS_PER_SECOND) as u32 +} + +/// . +/// Converts LDT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LDT_TO_LTOD(input: i64) -> i64 { + LDATE_AND_TIME_TO_LTIME_OF_DAY(input) +} + +/// . +/// Converts LDT to TOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LDT_TO_TOD(input: i64) -> u32 { + (LDT_TO_LTOD(input) / NANOS_PER_MILLISECOND) as u32 +} + +/// . +/// Converts DT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DT_TO_LDT(input: u32) -> i64 { + (input as i64) * NANOS_PER_SECOND +} + +/// . +/// Converts DT to DATE +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DT_TO_DATE(input: u32) -> u32 { + (input / SECONDS_PER_DAY) * SECONDS_PER_DAY +} + +/// . +/// Converts DT to LDATE +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DT_TO_LDATE(input: u32) -> i64 { + (DT_TO_DATE(input) as i64) * NANOS_PER_SECOND +} + +/// . +/// Converts DT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DT_TO_LTOD(input: u32) -> i64 { + LDT_TO_LTOD(DT_TO_LDT(input)) +} + +/// . +/// Converts DT to TOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn DT_TO_TOD(input: u32) -> u32 { + (DT_TO_LTOD(input) / NANOS_PER_MILLISECOND) as u32 +} + +/// . +/// Converts LTOD to TOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn LTOD_TO_TOD(input: i64) -> u32 { + (input / NANOS_PER_MILLISECOND) as u32 +} + +/// . +/// Converts TOD to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn TOD_TO_LTOD(input: u32) -> i64 { + (input as i64) * NANOS_PER_MILLISECOND +} diff --git a/libs/stdlib/src/date_time_extra_functions.rs b/libs/stdlib/src/date_time_extra_functions.rs index 9eb7dd9c91a..0647020eaa7 100644 --- a/libs/stdlib/src/date_time_extra_functions.rs +++ b/libs/stdlib/src/date_time_extra_functions.rs @@ -1,23 +1,52 @@ use chrono::{Datelike, NaiveDate, TimeZone, Timelike}; +const MILLIS_PER_SECOND: u32 = 1_000; +const MILLIS_PER_DAY: u32 = 60 * 60 * 24 * MILLIS_PER_SECOND; +const NANOS_PER_MILLISECOND: i64 = 1_000 * 1_000; +const NANOS_PER_SECOND: i64 = 1_000 * 1_000 * 1_000; + +fn dt_from_epoch_seconds(seconds: u32) -> chrono::DateTime { + chrono::Utc.timestamp_opt(seconds as i64, 0).single().expect("Out of range") +} + +fn split_tod_fields(millis: u32) -> (u32, u32, u32, u32) { + let total_millis = millis % MILLIS_PER_DAY; + let hour = total_millis / 3_600_000; + let minute = (total_millis / 60_000) % 60; + let second = (total_millis / MILLIS_PER_SECOND) % 60; + let millisecond = total_millis % MILLIS_PER_SECOND; + + (hour, minute, second, millisecond) +} + +fn split_ltod_fields(nanos: i64) -> (u32, u32, u32, u32) { + let millis = (nanos / NANOS_PER_MILLISECOND) as u32; + + split_tod_fields(millis) +} + +fn split_ldt_fields(nanos: i64) -> (i32, u32, u32, u32, u32, u32, u32) { + let dt = chrono::Utc.timestamp_nanos(nanos); + + (dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute(), dt.second(), dt.timestamp_subsec_millis()) +} + /// . /// Concatenates DATE and TOD to DT /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE_TOD(in1: i64, in2: i64) -> i64 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); - let tod = chrono::Utc.timestamp_nanos(in2); - let hour = tod.hour(); - let min = tod.minute(); - let sec = tod.second(); - let nano = tod.timestamp_subsec_nanos(); +pub extern "C" fn CONCAT_DATE_TOD(in1: u32, in2: u32) -> u32 { + in1 + in2 / MILLIS_PER_SECOND +} - date.and_hms_nano_opt(hour, min, sec, nano) - .expect("Invalid input") - .and_utc() - .timestamp_nanos_opt() - .expect("Out of range, cannot create Date") +/// . +/// Concatenates DATE and LTOD to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_DATE_LTOD(in1: u32, in2: i64) -> i64 { + (in1 as i64) * NANOS_PER_SECOND + in2 } /// . @@ -25,7 +54,7 @@ pub extern "C" fn CONCAT_DATE_TOD(in1: i64, in2: i64) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__INT(in1: i16, in2: i16, in3: i16) -> i64 { +pub extern "C" fn CONCAT_DATE__INT(in1: i16, in2: i16, in3: i16) -> u32 { concat_date(in1.into(), in2 as u32, in3 as u32) } @@ -34,7 +63,7 @@ pub extern "C" fn CONCAT_DATE__INT(in1: i16, in2: i16, in3: i16) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__UINT(in1: u16, in2: u16, in3: u16) -> i64 { +pub extern "C" fn CONCAT_DATE__UINT(in1: u16, in2: u16, in3: u16) -> u32 { concat_date(in1.into(), in2.into(), in3.into()) } @@ -43,7 +72,7 @@ pub extern "C" fn CONCAT_DATE__UINT(in1: u16, in2: u16, in3: u16) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__DINT(in1: i32, in2: i32, in3: i32) -> i64 { +pub extern "C" fn CONCAT_DATE__DINT(in1: i32, in2: i32, in3: i32) -> u32 { concat_date(in1, in2 as u32, in3 as u32) } @@ -52,7 +81,7 @@ pub extern "C" fn CONCAT_DATE__DINT(in1: i32, in2: i32, in3: i32) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__UDINT(in1: u32, in2: u32, in3: u32) -> i64 { +pub extern "C" fn CONCAT_DATE__UDINT(in1: u32, in2: u32, in3: u32) -> u32 { concat_date(in1 as i32, in2, in3) } @@ -61,7 +90,7 @@ pub extern "C" fn CONCAT_DATE__UDINT(in1: u32, in2: u32, in3: u32) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__LINT(in1: i64, in2: i64, in3: i64) -> i64 { +pub extern "C" fn CONCAT_DATE__LINT(in1: i64, in2: i64, in3: i64) -> u32 { concat_date(in1 as i32, in2 as u32, in3 as u32) } @@ -70,7 +99,7 @@ pub extern "C" fn CONCAT_DATE__LINT(in1: i64, in2: i64, in3: i64) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_DATE__ULINT(in1: u64, in2: u64, in3: u64) -> i64 { +pub extern "C" fn CONCAT_DATE__ULINT(in1: u64, in2: u64, in3: u64) -> u32 { concat_date(in1 as i32, in2 as u32, in3 as u32) } @@ -79,12 +108,12 @@ pub extern "C" fn CONCAT_DATE__ULINT(in1: u64, in2: u64, in3: u64) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn concat_date(in1: i32, in2: u32, in3: u32) -> i64 { +pub extern "C" fn concat_date(in1: i32, in2: u32, in3: u32) -> u32 { let dt = NaiveDate::from_ymd_opt(in1, in2, in3) .and_then(|date| date.and_hms_opt(0, 0, 0)) .expect("Invalid parameters, cannot create date"); - dt.and_utc().timestamp_nanos_opt().expect("Out of range, cannot create date") + dt.and_utc().timestamp() as u32 } /// . @@ -92,7 +121,7 @@ pub extern "C" fn concat_date(in1: i32, in2: u32, in3: u32) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__SINT(in1: i8, in2: i8, in3: i8, in4: i8) -> i64 { +pub extern "C" fn CONCAT_TOD__SINT(in1: i8, in2: i8, in3: i8, in4: i8) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -101,7 +130,7 @@ pub extern "C" fn CONCAT_TOD__SINT(in1: i8, in2: i8, in3: i8, in4: i8) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__USINT(in1: u8, in2: u8, in3: u8, in4: u8) -> i64 { +pub extern "C" fn CONCAT_TOD__USINT(in1: u8, in2: u8, in3: u8, in4: u8) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -110,7 +139,7 @@ pub extern "C" fn CONCAT_TOD__USINT(in1: u8, in2: u8, in3: u8, in4: u8) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__INT(in1: i16, in2: i16, in3: i16, in4: i16) -> i64 { +pub extern "C" fn CONCAT_TOD__INT(in1: i16, in2: i16, in3: i16, in4: i16) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -119,7 +148,7 @@ pub extern "C" fn CONCAT_TOD__INT(in1: i16, in2: i16, in3: i16, in4: i16) -> i64 /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__UINT(in1: u16, in2: u16, in3: u16, in4: u16) -> i64 { +pub extern "C" fn CONCAT_TOD__UINT(in1: u16, in2: u16, in3: u16, in4: u16) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -128,7 +157,7 @@ pub extern "C" fn CONCAT_TOD__UINT(in1: u16, in2: u16, in3: u16, in4: u16) -> i6 /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__DINT(in1: i32, in2: i32, in3: i32, in4: i32) -> i64 { +pub extern "C" fn CONCAT_TOD__DINT(in1: i32, in2: i32, in3: i32, in4: i32) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -137,7 +166,7 @@ pub extern "C" fn CONCAT_TOD__DINT(in1: i32, in2: i32, in3: i32, in4: i32) -> i6 /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__UDINT(in1: u32, in2: u32, in3: u32, in4: u32) -> i64 { +pub extern "C" fn CONCAT_TOD__UDINT(in1: u32, in2: u32, in3: u32, in4: u32) -> u32 { concat_tod(in1, in2, in3, in4) } @@ -146,7 +175,7 @@ pub extern "C" fn CONCAT_TOD__UDINT(in1: u32, in2: u32, in3: u32, in4: u32) -> i /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__LINT(in1: i64, in2: i64, in3: i64, in4: i64) -> i64 { +pub extern "C" fn CONCAT_TOD__LINT(in1: i64, in2: i64, in3: i64, in4: i64) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } @@ -155,21 +184,224 @@ pub extern "C" fn CONCAT_TOD__LINT(in1: i64, in2: i64, in3: i64, in4: i64) -> i6 /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn CONCAT_TOD__ULINT(in1: u64, in2: u64, in3: u64, in4: u64) -> i64 { +pub extern "C" fn CONCAT_TOD__ULINT(in1: u64, in2: u64, in3: u64, in4: u64) -> u32 { concat_tod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) } +/// . +/// Concatenates hour, minute, second, millisecond of type SINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__SINT(in1: i8, in2: i8, in3: i8, in4: i8) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type USINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__USINT(in1: u8, in2: u8, in3: u8, in4: u8) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type INT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__INT(in1: i16, in2: i16, in3: i16, in4: i16) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type UINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__UINT(in1: u16, in2: u16, in3: u16, in4: u16) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type DINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__DINT(in1: i32, in2: i32, in3: i32, in4: i32) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type UDINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__UDINT(in1: u32, in2: u32, in3: u32, in4: u32) -> i64 { + concat_ltod(in1, in2, in3, in4) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type LINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__LINT(in1: i64, in2: i64, in3: i64, in4: i64) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates hour, minute, second, millisecond of type ULINT to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LTOD__ULINT(in1: u64, in2: u64, in3: u64, in4: u64) -> i64 { + concat_ltod(in1 as u32, in2 as u32, in3 as u32, in4 as u32) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type INT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__INT( + in1: i16, + in2: i16, + in3: i16, + in4: i16, + in5: i16, + in6: i16, + in7: i16, +) -> i64 { + concat_ldt(in1.into(), in2 as u32, in3 as u32, in4 as u32, in5 as u32, in6 as u32, in7 as u32) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type UINT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__UINT( + in1: u16, + in2: u16, + in3: u16, + in4: u16, + in5: u16, + in6: u16, + in7: u16, +) -> i64 { + concat_ldt(in1.into(), in2.into(), in3.into(), in4.into(), in5.into(), in6.into(), in7.into()) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type DINT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__DINT( + in1: i32, + in2: i32, + in3: i32, + in4: i32, + in5: i32, + in6: i32, + in7: i32, +) -> i64 { + concat_ldt(in1, in2 as u32, in3 as u32, in4 as u32, in5 as u32, in6 as u32, in7 as u32) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type UDINT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__UDINT( + in1: u32, + in2: u32, + in3: u32, + in4: u32, + in5: u32, + in6: u32, + in7: u32, +) -> i64 { + concat_ldt(in1 as i32, in2, in3, in4, in5, in6, in7) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type LINT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__LINT( + in1: i64, + in2: i64, + in3: i64, + in4: i64, + in5: i64, + in6: i64, + in7: i64, +) -> i64 { + concat_ldt(in1 as i32, in2 as u32, in3 as u32, in4 as u32, in5 as u32, in6 as u32, in7 as u32) +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond of type ULINT to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn CONCAT_LDT__ULINT( + in1: u64, + in2: u64, + in3: u64, + in4: u64, + in5: u64, + in6: u64, + in7: u64, +) -> i64 { + concat_ldt(in1 as i32, in2 as u32, in3 as u32, in4 as u32, in5 as u32, in6 as u32, in7 as u32) +} + /// . /// Concatenates hour, minute, second, millisecond to TOD /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn concat_tod(in1: u32, in2: u32, in3: u32, in4: u32) -> i64 { - let dt = NaiveDate::from_ymd_opt(1970, 1, 1) +pub extern "C" fn concat_tod(in1: u32, in2: u32, in3: u32, in4: u32) -> u32 { + NaiveDate::from_ymd_opt(1970, 1, 1) .and_then(|date| date.and_hms_milli_opt(in1, in2, in3, in4)) .expect("Invalid parameters, cannot create TOD"); - dt.and_utc().timestamp_nanos_opt().expect("Out of range, cannot create TOD") + ((in1 * 3_600 + in2 * 60 + in3) * MILLIS_PER_SECOND) + in4 +} + +/// . +/// Concatenates hour, minute, second, millisecond to LTOD +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn concat_ltod(in1: u32, in2: u32, in3: u32, in4: u32) -> i64 { + (concat_tod(in1, in2, in3, in4) as i64) * NANOS_PER_MILLISECOND +} + +/// . +/// Concatenates year, month, day, hour, minute, second, millisecond to LDT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn concat_ldt( + year: i32, + month: u32, + day: u32, + hour: u32, + minute: u32, + second: u32, + millisecond: u32, +) -> i64 { + let date = concat_date(year, month, day); + let tod = concat_ltod(hour, minute, second, millisecond); + + CONCAT_DATE_LTOD(date, tod) } /// . @@ -177,8 +409,8 @@ pub extern "C" fn concat_tod(in1: u32, in2: u32, in3: u32, in4: u32) -> i64 { /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__INT(in1: i64, out1: &mut i16, out2: &mut i16, out3: &mut i16) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__INT(in1: u32, out1: &mut i16, out2: &mut i16, out3: &mut i16) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); // if year does not fit in target data type -> panic *out1 = date.year().try_into().unwrap(); *out2 = date.month() as i16; @@ -193,8 +425,8 @@ pub extern "C" fn SPLIT_DATE__INT(in1: i64, out1: &mut i16, out2: &mut i16, out3 /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__UINT(in1: i64, out1: &mut u16, out2: &mut u16, out3: &mut u16) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__UINT(in1: u32, out1: &mut u16, out2: &mut u16, out3: &mut u16) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); // if year does not fit in target data type -> panic *out1 = date.year().try_into().unwrap(); *out2 = date.month() as u16; @@ -208,8 +440,8 @@ pub extern "C" fn SPLIT_DATE__UINT(in1: i64, out1: &mut u16, out2: &mut u16, out /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__DINT(in1: i64, out1: &mut i32, out2: &mut i32, out3: &mut i32) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__DINT(in1: u32, out1: &mut i32, out2: &mut i32, out3: &mut i32) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); *out1 = date.year(); *out2 = date.month() as i32; *out3 = date.day() as i32; @@ -222,8 +454,8 @@ pub extern "C" fn SPLIT_DATE__DINT(in1: i64, out1: &mut i32, out2: &mut i32, out /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__UDINT(in1: i64, out1: &mut u32, out2: &mut u32, out3: &mut u32) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__UDINT(in1: u32, out1: &mut u32, out2: &mut u32, out3: &mut u32) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); // if year does not fit in target data type -> panic *out1 = date.year().try_into().unwrap(); *out2 = date.month(); @@ -237,8 +469,8 @@ pub extern "C" fn SPLIT_DATE__UDINT(in1: i64, out1: &mut u32, out2: &mut u32, ou /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__LINT(in1: i64, out1: &mut i64, out2: &mut i64, out3: &mut i64) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__LINT(in1: u32, out1: &mut i64, out2: &mut i64, out3: &mut i64) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); // if year does not fit in target data type -> panic *out1 = date.year().into(); *out2 = date.month() as i64; @@ -253,8 +485,8 @@ pub extern "C" fn SPLIT_DATE__LINT(in1: i64, out1: &mut i64, out2: &mut i64, out /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SPLIT_DATE__ULINT(in1: i64, out1: &mut u64, out2: &mut u64, out3: &mut u64) -> i16 { - let date = chrono::Utc.timestamp_nanos(in1).date_naive(); +pub extern "C" fn SPLIT_DATE__ULINT(in1: u32, out1: &mut u64, out2: &mut u64, out3: &mut u64) -> i16 { + let date = dt_from_epoch_seconds(in1).date_naive(); // if year does not fit in target data type -> panic *out1 = date.year().try_into().unwrap(); *out2 = date.month() as u64; @@ -269,17 +501,17 @@ pub extern "C" fn SPLIT_DATE__ULINT(in1: i64, out1: &mut u64, out2: &mut u64, ou #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__INT( - in1: i64, + in1: u32, out1: &mut i16, out2: &mut i16, out3: &mut i16, out4: &mut i16, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour() as i16; - *out2 = tod.minute() as i16; - *out3 = tod.second() as i16; - *out4 = tod.timestamp_subsec_millis() as i16; + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour as i16; + *out2 = minute as i16; + *out3 = second as i16; + *out4 = millisecond as i16; 0 } @@ -290,17 +522,17 @@ pub extern "C" fn SPLIT_TOD__INT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__UINT( - in1: i64, + in1: u32, out1: &mut u16, out2: &mut u16, out3: &mut u16, out4: &mut u16, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour() as u16; - *out2 = tod.minute() as u16; - *out3 = tod.second() as u16; - *out4 = tod.timestamp_subsec_millis() as u16; + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour as u16; + *out2 = minute as u16; + *out3 = second as u16; + *out4 = millisecond as u16; 0 } @@ -311,17 +543,17 @@ pub extern "C" fn SPLIT_TOD__UINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__DINT( - in1: i64, + in1: u32, out1: &mut i32, out2: &mut i32, out3: &mut i32, out4: &mut i32, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour() as i32; - *out2 = tod.minute() as i32; - *out3 = tod.second() as i32; - *out4 = tod.timestamp_subsec_millis() as i32; + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour as i32; + *out2 = minute as i32; + *out3 = second as i32; + *out4 = millisecond as i32; 0 } @@ -332,17 +564,17 @@ pub extern "C" fn SPLIT_TOD__DINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__UDINT( - in1: i64, + in1: u32, out1: &mut u32, out2: &mut u32, out3: &mut u32, out4: &mut u32, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour(); - *out2 = tod.minute(); - *out3 = tod.second(); - *out4 = tod.timestamp_subsec_millis(); + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour; + *out2 = minute; + *out3 = second; + *out4 = millisecond; 0 } @@ -353,17 +585,17 @@ pub extern "C" fn SPLIT_TOD__UDINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__LINT( - in1: i64, + in1: u32, out1: &mut i64, out2: &mut i64, out3: &mut i64, out4: &mut i64, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour() as i64; - *out2 = tod.minute() as i64; - *out3 = tod.second() as i64; - *out4 = tod.timestamp_subsec_millis() as i64; + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour as i64; + *out2 = minute as i64; + *out3 = second as i64; + *out4 = millisecond as i64; 0 } @@ -374,17 +606,143 @@ pub extern "C" fn SPLIT_TOD__LINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_TOD__ULINT( + in1: u32, + out1: &mut u64, + out2: &mut u64, + out3: &mut u64, + out4: &mut u64, +) -> i16 { + let (hour, minute, second, millisecond) = split_tod_fields(in1); + *out1 = hour as u64; + *out2 = minute as u64; + *out3 = second as u64; + *out4 = millisecond as u64; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type INT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__INT( + in1: i64, + out1: &mut i16, + out2: &mut i16, + out3: &mut i16, + out4: &mut i16, +) -> i16 { + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour as i16; + *out2 = minute as i16; + *out3 = second as i16; + *out4 = millisecond as i16; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type UINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__UINT( + in1: i64, + out1: &mut u16, + out2: &mut u16, + out3: &mut u16, + out4: &mut u16, +) -> i16 { + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour as u16; + *out2 = minute as u16; + *out3 = second as u16; + *out4 = millisecond as u16; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type DINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__DINT( + in1: i64, + out1: &mut i32, + out2: &mut i32, + out3: &mut i32, + out4: &mut i32, +) -> i16 { + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour as i32; + *out2 = minute as i32; + *out3 = second as i32; + *out4 = millisecond as i32; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type UDINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__UDINT( + in1: i64, + out1: &mut u32, + out2: &mut u32, + out3: &mut u32, + out4: &mut u32, +) -> i16 { + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour; + *out2 = minute; + *out3 = second; + *out4 = millisecond; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type LINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__LINT( + in1: i64, + out1: &mut i64, + out2: &mut i64, + out3: &mut i64, + out4: &mut i64, +) -> i16 { + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour as i64; + *out2 = minute as i64; + *out3 = second as i64; + *out4 = millisecond as i64; + + 0 +} + +/// . +/// Splits LTOD into hour, minute, second, millisecond of type ULINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LTOD__ULINT( in1: i64, out1: &mut u64, out2: &mut u64, out3: &mut u64, out4: &mut u64, ) -> i16 { - let tod = chrono::Utc.timestamp_nanos(in1); - *out1 = tod.hour() as u64; - *out2 = tod.minute() as u64; - *out3 = tod.second() as u64; - *out4 = tod.timestamp_subsec_millis() as u64; + let (hour, minute, second, millisecond) = split_ltod_fields(in1); + *out1 = hour as u64; + *out2 = minute as u64; + *out3 = second as u64; + *out4 = millisecond as u64; 0 } @@ -395,7 +753,7 @@ pub extern "C" fn SPLIT_TOD__ULINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__INT( - in1: i64, + in1: u32, out1: &mut i16, out2: &mut i16, out3: &mut i16, @@ -404,7 +762,7 @@ pub extern "C" fn SPLIT_DT__INT( out6: &mut i16, out7: &mut i16, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); // if year does not fit in target data type -> panic *out1 = dt.year().try_into().unwrap(); *out2 = dt.month() as i16; @@ -412,7 +770,7 @@ pub extern "C" fn SPLIT_DT__INT( *out4 = dt.hour() as i16; *out5 = dt.minute() as i16; *out6 = dt.second() as i16; - *out7 = dt.timestamp_subsec_millis() as i16; + *out7 = 0; 0 } @@ -423,7 +781,7 @@ pub extern "C" fn SPLIT_DT__INT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__UINT( - in1: i64, + in1: u32, out1: &mut u16, out2: &mut u16, out3: &mut u16, @@ -432,7 +790,7 @@ pub extern "C" fn SPLIT_DT__UINT( out6: &mut u16, out7: &mut u16, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); // if year does not fit in target data type -> panic *out1 = dt.year().try_into().unwrap(); *out2 = dt.month() as u16; @@ -440,7 +798,7 @@ pub extern "C" fn SPLIT_DT__UINT( *out4 = dt.hour() as u16; *out5 = dt.minute() as u16; *out6 = dt.second() as u16; - *out7 = dt.timestamp_subsec_millis() as u16; + *out7 = 0; 0 } @@ -451,7 +809,7 @@ pub extern "C" fn SPLIT_DT__UINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__DINT( - in1: i64, + in1: u32, out1: &mut i32, out2: &mut i32, out3: &mut i32, @@ -460,14 +818,14 @@ pub extern "C" fn SPLIT_DT__DINT( out6: &mut i32, out7: &mut i32, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); *out1 = dt.year(); *out2 = dt.month() as i32; *out3 = dt.day() as i32; *out4 = dt.hour() as i32; *out5 = dt.minute() as i32; *out6 = dt.second() as i32; - *out7 = dt.timestamp_subsec_millis() as i32; + *out7 = 0; 0 } @@ -478,7 +836,7 @@ pub extern "C" fn SPLIT_DT__DINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__UDINT( - in1: i64, + in1: u32, out1: &mut u32, out2: &mut u32, out3: &mut u32, @@ -487,7 +845,7 @@ pub extern "C" fn SPLIT_DT__UDINT( out6: &mut u32, out7: &mut u32, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); // if year does not fit in target data type -> panic *out1 = dt.year().try_into().unwrap(); *out2 = dt.month(); @@ -495,7 +853,7 @@ pub extern "C" fn SPLIT_DT__UDINT( *out4 = dt.hour(); *out5 = dt.minute(); *out6 = dt.second(); - *out7 = dt.timestamp_subsec_millis(); + *out7 = 0; 0 } @@ -506,7 +864,7 @@ pub extern "C" fn SPLIT_DT__UDINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__LINT( - in1: i64, + in1: u32, out1: &mut i64, out2: &mut i64, out3: &mut i64, @@ -515,7 +873,7 @@ pub extern "C" fn SPLIT_DT__LINT( out6: &mut i64, out7: &mut i64, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); // if year does not fit in target data type -> panic *out1 = dt.year().into(); *out2 = dt.month() as i64; @@ -523,7 +881,7 @@ pub extern "C" fn SPLIT_DT__LINT( *out4 = dt.hour() as i64; *out5 = dt.minute() as i64; *out6 = dt.second() as i64; - *out7 = dt.timestamp_subsec_millis() as i64; + *out7 = 0; 0 } @@ -534,7 +892,7 @@ pub extern "C" fn SPLIT_DT__LINT( #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn SPLIT_DT__ULINT( - in1: i64, + in1: u32, out1: &mut u64, out2: &mut u64, out3: &mut u64, @@ -543,7 +901,7 @@ pub extern "C" fn SPLIT_DT__ULINT( out6: &mut u64, out7: &mut u64, ) -> i16 { - let dt = chrono::Utc.timestamp_nanos(in1); + let dt = dt_from_epoch_seconds(in1); // if year does not fit in target data type -> panic *out1 = dt.year().try_into().unwrap(); *out2 = dt.month() as u64; @@ -551,7 +909,169 @@ pub extern "C" fn SPLIT_DT__ULINT( *out4 = dt.hour() as u64; *out5 = dt.minute() as u64; *out6 = dt.second() as u64; - *out7 = dt.timestamp_subsec_millis() as u64; + *out7 = 0; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type INT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__INT( + in1: i64, + out1: &mut i16, + out2: &mut i16, + out3: &mut i16, + out4: &mut i16, + out5: &mut i16, + out6: &mut i16, + out7: &mut i16, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year.try_into().unwrap(); + *out2 = month as i16; + *out3 = day as i16; + *out4 = hour as i16; + *out5 = minute as i16; + *out6 = second as i16; + *out7 = millisecond as i16; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type UINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__UINT( + in1: i64, + out1: &mut u16, + out2: &mut u16, + out3: &mut u16, + out4: &mut u16, + out5: &mut u16, + out6: &mut u16, + out7: &mut u16, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year.try_into().unwrap(); + *out2 = month as u16; + *out3 = day as u16; + *out4 = hour as u16; + *out5 = minute as u16; + *out6 = second as u16; + *out7 = millisecond as u16; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type DINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__DINT( + in1: i64, + out1: &mut i32, + out2: &mut i32, + out3: &mut i32, + out4: &mut i32, + out5: &mut i32, + out6: &mut i32, + out7: &mut i32, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year; + *out2 = month as i32; + *out3 = day as i32; + *out4 = hour as i32; + *out5 = minute as i32; + *out6 = second as i32; + *out7 = millisecond as i32; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type UDINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__UDINT( + in1: i64, + out1: &mut u32, + out2: &mut u32, + out3: &mut u32, + out4: &mut u32, + out5: &mut u32, + out6: &mut u32, + out7: &mut u32, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year.try_into().unwrap(); + *out2 = month; + *out3 = day; + *out4 = hour; + *out5 = minute; + *out6 = second; + *out7 = millisecond; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type LINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__LINT( + in1: i64, + out1: &mut i64, + out2: &mut i64, + out3: &mut i64, + out4: &mut i64, + out5: &mut i64, + out6: &mut i64, + out7: &mut i64, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year.into(); + *out2 = month as i64; + *out3 = day as i64; + *out4 = hour as i64; + *out5 = minute as i64; + *out6 = second as i64; + *out7 = millisecond as i64; + + 0 +} + +/// . +/// Splits LDT into year, month, day, hour, minute, second, millisecond of type ULINT +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn SPLIT_LDT__ULINT( + in1: i64, + out1: &mut u64, + out2: &mut u64, + out3: &mut u64, + out4: &mut u64, + out5: &mut u64, + out6: &mut u64, + out7: &mut u64, +) -> i16 { + let (year, month, day, hour, minute, second, millisecond) = split_ldt_fields(in1); + *out1 = year.try_into().unwrap(); + *out2 = month as u64; + *out3 = day as u64; + *out4 = hour as u64; + *out5 = minute as u64; + *out6 = second as u64; + *out7 = millisecond as u64; 0 } @@ -561,7 +1081,7 @@ pub extern "C" fn SPLIT_DT__ULINT( /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn DAY_OF_WEEK(in1: i64) -> i8 { - let date = chrono::Utc.timestamp_nanos(in1); +pub extern "C" fn DAY_OF_WEEK(in1: u32) -> i8 { + let date = dt_from_epoch_seconds(in1); date.weekday().num_days_from_sunday() as i8 } diff --git a/libs/stdlib/src/date_time_numeric_functions.rs b/libs/stdlib/src/date_time_numeric_functions.rs index 0b17bb7e60c..29b3a2ebcc1 100644 --- a/libs/stdlib/src/date_time_numeric_functions.rs +++ b/libs/stdlib/src/date_time_numeric_functions.rs @@ -1,37 +1,45 @@ use chrono::TimeZone; +const MILLIS_PER_SECOND: u32 = 1_000; +const MILLIS_PER_DAY: u32 = 60 * 60 * 24 * MILLIS_PER_SECOND; + +fn checked_millis_to_seconds(input: u32) -> u32 { + input / MILLIS_PER_SECOND +} + +fn checked_seconds_to_millis(input: u32) -> u32 { + input.checked_mul(MILLIS_PER_SECOND).unwrap() +} + /// . /// This operator returns the value of adding up two TIME operands. -/// Panic on overflow +/// Panics on overflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn ADD_TIME(in1: i64, in2: i64) -> i64 { - chrono::Duration::nanoseconds(in1) - .checked_add(&chrono::Duration::nanoseconds(in2)) - .unwrap() - .num_nanoseconds() - .unwrap() +pub extern "C-unwind" fn ADD_TIME(in1: u32, in2: u32) -> u32 { + in1.checked_add(in2).unwrap() } /// . /// This operator returns the value of adding up TOD and TIME. -/// Panic on overflow +/// Wraps around day boundaries. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn ADD_TOD_TIME(in1: i64, in2: i64) -> i64 { - add_datetime_time(in1, in2) +pub extern "C-unwind" fn ADD_TOD_TIME(in1: u32, in2: u32) -> u32 { + ((in1 as u64 + in2 as u64) % MILLIS_PER_DAY as u64) as u32 } /// . /// This operator returns the value of adding up DT and TIME. -/// Panic on overflow +/// Panics on overflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn ADD_DT_TIME(in1: i64, in2: i64) -> i64 { - add_datetime_time(in1, in2) +pub extern "C-unwind" fn ADD_DT_TIME(in1: u32, in2: u32) -> u32 { + let time_seconds = checked_millis_to_seconds(in2); + in1.checked_add(time_seconds).unwrap() } fn add_datetime_time(in1: i64, in2: i64) -> i64 { @@ -45,46 +53,42 @@ fn add_datetime_time(in1: i64, in2: i64) -> i64 { /// . /// This operator produces the subtraction of two TIME operands -/// Panic on overflow +/// Panics on underflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_TIME(in1: i64, in2: i64) -> i64 { - chrono::Duration::nanoseconds(in1) - .checked_sub(&chrono::Duration::nanoseconds(in2)) - .unwrap() - .num_nanoseconds() - .unwrap() +pub extern "C-unwind" fn SUB_TIME(in1: u32, in2: u32) -> u32 { + in1.checked_sub(in2).unwrap() } /// . /// This operator produces the subtraction of two DATE operands -/// Panic on overflow +/// Panics on underflow and when the resulting TIME would overflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_DATE_DATE(in1: i64, in2: i64) -> i64 { - sub_datetimes(in1, in2) +pub extern "C-unwind" fn SUB_DATE_DATE(in1: u32, in2: u32) -> u32 { + checked_seconds_to_millis(in1.checked_sub(in2).unwrap()) } /// . /// This operator produces the subtraction of TOD and TIME -/// Panic on overflow +/// Wraps around day boundaries. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_TOD_TIME(in1: i64, in2: i64) -> i64 { - sub_datetime_duration(in1, in2) +pub extern "C-unwind" fn SUB_TOD_TIME(in1: u32, in2: u32) -> u32 { + ((in1 as u64 + MILLIS_PER_DAY as u64 - (in2 % MILLIS_PER_DAY) as u64) % MILLIS_PER_DAY as u64) as u32 } /// . /// This operator produces the subtraction of two TOD operands -/// Panic on overflow +/// Panics on underflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_TOD_TOD(in1: i64, in2: i64) -> i64 { - sub_datetimes(in1, in2) +pub extern "C-unwind" fn SUB_TOD_TOD(in1: u32, in2: u32) -> u32 { + in1.checked_sub(in2).unwrap() } fn sub_datetimes(in1: i64, in2: i64) -> i64 { @@ -97,12 +101,13 @@ fn sub_datetimes(in1: i64, in2: i64) -> i64 { /// . /// This operator produces the subtraction of DT and TIME -/// Panic on overflow +/// Panics on underflow. /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_DT_TIME(in1: i64, in2: i64) -> i64 { - sub_datetime_duration(in1, in2) +pub extern "C-unwind" fn SUB_DT_TIME(in1: u32, in2: u32) -> u32 { + let time_seconds = checked_millis_to_seconds(in2); + in1.checked_sub(time_seconds).unwrap() } fn sub_datetime_duration(in1: i64, in2: i64) -> i64 { @@ -116,12 +121,102 @@ fn sub_datetime_duration(in1: i64, in2: i64) -> i64 { /// . /// This operator produces the subtraction of two DT operands +/// Panics on underflow and when the resulting TIME would overflow. +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_DT_DT(in1: u32, in2: u32) -> u32 { + checked_seconds_to_millis(in1.checked_sub(in2).unwrap()) +} + +/// . +/// This operator returns the value of adding up two LTIME operands. /// Panic on overflow /// #[allow(non_snake_case)] #[no_mangle] -pub extern "C-unwind" fn SUB_DT_DT(in1: i64, in2: i64) -> i64 { - sub_datetimes(in1, in2) +pub extern "C-unwind" fn ADD_LTIME(in1: i64, in2: i64) -> i64 { + ADD__LTIME__LTIME(in1, in2) +} + +/// . +/// This operator returns the value of adding up LTOD and LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD_LTOD_LTIME(in1: i64, in2: i64) -> i64 { + ADD__LTOD__LTIME(in1, in2) +} + +/// . +/// This operator returns the value of adding up LDT and LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD_LDT_LTIME(in1: i64, in2: i64) -> i64 { + ADD__LDT__LTIME(in1, in2) +} + +/// . +/// This operator produces the subtraction of two LTIME operands. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LTIME(in1: i64, in2: i64) -> i64 { + SUB__LTIME__LTIME(in1, in2) +} + +/// . +/// This operator produces the subtraction of two LDATE operands. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LDATE_LDATE(in1: i64, in2: i64) -> i64 { + SUB__LDATE__LDATE(in1, in2) +} + +/// . +/// This operator produces the subtraction of LTOD and LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LTOD_LTIME(in1: i64, in2: i64) -> i64 { + SUB__LTOD__LTIME(in1, in2) +} + +/// . +/// This operator produces the subtraction of two LTOD operands. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LTOD_LTOD(in1: i64, in2: i64) -> i64 { + SUB__LTOD__LTOD(in1, in2) +} + +/// . +/// This operator produces the subtraction of LDT and LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LDT_LTIME(in1: i64, in2: i64) -> i64 { + SUB__LDT__LTIME(in1, in2) +} + +/// . +/// This operator produces the subtraction of two LDT operands. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB_LDT_LDT(in1: i64, in2: i64) -> i64 { + SUB__LDT__LDT(in1, in2) } /// . @@ -794,6 +889,356 @@ pub extern "C-unwind" fn DIV__TIME__LREAL(in1: i64, in2: f64) -> i64 { checked_div_time_by_f64(in1, in2) } +/// . +/// Compatibility alias for multiplying LTIME by SINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__SINT(in1: i64, in2: i8) -> i64 { + MUL_LTIME__SINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by INT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__INT(in1: i64, in2: i16) -> i64 { + MUL_LTIME__INT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by DINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__DINT(in1: i64, in2: i32) -> i64 { + MUL_LTIME__DINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by LINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__LINT(in1: i64, in2: i64) -> i64 { + MUL_LTIME__LINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by USINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__USINT(in1: i64, in2: u8) -> i64 { + MUL_LTIME__USINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by UINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__UINT(in1: i64, in2: u16) -> i64 { + MUL_LTIME__UINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by UDINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__UDINT(in1: i64, in2: u32) -> i64 { + MUL_LTIME__UDINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by ULINT. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__ULINT(in1: i64, in2: u64) -> i64 { + MUL_LTIME__ULINT(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by REAL. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__REAL(in1: i64, in2: f32) -> i64 { + MUL_LTIME__REAL(in1, in2) +} + +/// . +/// Compatibility alias for multiplying LTIME by LREAL. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn MUL__LTIME__LREAL(in1: i64, in2: f64) -> i64 { + MUL_LTIME__LREAL(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by SINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__SINT(in1: i64, in2: i8) -> i64 { + DIV_LTIME__SINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by INT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__INT(in1: i64, in2: i16) -> i64 { + DIV_LTIME__INT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by DINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__DINT(in1: i64, in2: i32) -> i64 { + DIV_LTIME__DINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by LINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__LINT(in1: i64, in2: i64) -> i64 { + DIV_LTIME__LINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by USINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__USINT(in1: i64, in2: u8) -> i64 { + DIV_LTIME__USINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by UINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__UINT(in1: i64, in2: u16) -> i64 { + DIV_LTIME__UINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by UDINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__UDINT(in1: i64, in2: u32) -> i64 { + DIV_LTIME__UDINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by ULINT. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__ULINT(in1: i64, in2: u64) -> i64 { + DIV_LTIME__ULINT(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by REAL. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__REAL(in1: i64, in2: f32) -> i64 { + DIV_LTIME__REAL(in1, in2) +} + +/// . +/// Compatibility alias for dividing LTIME by LREAL. +/// Panic on overflow or division by zero +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn DIV__LTIME__LREAL(in1: i64, in2: f64) -> i64 { + DIV_LTIME__LREAL(in1, in2) +} + +/// . +/// Compatibility symbol for LTIME + LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD__LTIME__LTIME(in1: i64, in2: i64) -> i64 { + in1.checked_add(in2).unwrap() +} + +/// . +/// Compatibility symbol for LTOD + LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD__LTOD__LTIME(in1: i64, in2: i64) -> i64 { + add_datetime_time(in1, in2) +} + +/// . +/// Compatibility symbol for LDT + LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD__LDT__LTIME(in1: i64, in2: i64) -> i64 { + add_datetime_time(in1, in2) +} + +/// . +/// Compatibility symbol for LTIME - LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LTIME__LTIME(in1: i64, in2: i64) -> i64 { + in1.checked_sub(in2).unwrap() +} + +/// . +/// Compatibility symbol for LDATE - LDATE overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LDATE__LDATE(in1: i64, in2: i64) -> i64 { + sub_datetimes(in1, in2) +} + +/// . +/// Compatibility symbol for LTOD - LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LTOD__LTIME(in1: i64, in2: i64) -> i64 { + sub_datetime_duration(in1, in2) +} + +/// . +/// Compatibility symbol for LTOD - LTOD overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LTOD__LTOD(in1: i64, in2: i64) -> i64 { + sub_datetimes(in1, in2) +} + +/// . +/// Compatibility symbol for LDT - LTIME overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LDT__LTIME(in1: i64, in2: i64) -> i64 { + sub_datetime_duration(in1, in2) +} + +/// . +/// Compatibility symbol for LDT - LDT overload resolution. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LDT__LDT(in1: i64, in2: i64) -> i64 { + sub_datetimes(in1, in2) +} + +/// . +/// Compatibility alias for LDATE_AND_TIME + LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD__LDATE_AND_TIME__LTIME(in1: i64, in2: i64) -> i64 { + ADD__LDT__LTIME(in1, in2) +} + +/// . +/// Compatibility alias for LTIME_OF_DAY + LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn ADD__LTIME_OF_DAY__LTIME(in1: i64, in2: i64) -> i64 { + ADD__LTOD__LTIME(in1, in2) +} + +/// . +/// Compatibility alias for LDATE_AND_TIME - LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LDATE_AND_TIME__LTIME(in1: i64, in2: i64) -> i64 { + SUB__LDT__LTIME(in1, in2) +} + +/// . +/// Compatibility alias for LDATE_AND_TIME - LDATE_AND_TIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LDATE_AND_TIME__LDATE_AND_TIME(in1: i64, in2: i64) -> i64 { + SUB__LDT__LDT(in1, in2) +} + +/// . +/// Compatibility alias for LTIME_OF_DAY - LTIME. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LTIME_OF_DAY__LTIME(in1: i64, in2: i64) -> i64 { + SUB__LTOD__LTIME(in1, in2) +} + +/// . +/// Compatibility alias for LTIME_OF_DAY - LTIME_OF_DAY. +/// Panic on overflow +/// +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C-unwind" fn SUB__LTIME_OF_DAY__LTIME_OF_DAY(in1: i64, in2: i64) -> i64 { + SUB__LTOD__LTOD(in1, in2) +} + /// . /// Divide TIME by LREAL /// Panic on overflow or division by zero diff --git a/libs/stdlib/src/endianness_conversion_functions.rs b/libs/stdlib/src/endianness_conversion_functions.rs index 9c5b716546c..753aa6c91ce 100644 --- a/libs/stdlib/src/endianness_conversion_functions.rs +++ b/libs/stdlib/src/endianness_conversion_functions.rs @@ -52,9 +52,12 @@ define_endianness_for_int_types!(WORD, u16); define_endianness_for_int_types!(DWORD, u32); define_endianness_for_int_types!(LWORD, u64); define_endianness_for_int_types!(WCHAR, u16); -define_endianness_for_int_types!(DATE, i64); -define_endianness_for_int_types!(TIME_OF_DAY, i64); -define_endianness_for_int_types!(DATE_AND_TIME, i64); +define_endianness_for_int_types!(DATE, u32); +define_endianness_for_int_types!(TIME_OF_DAY, u32); +define_endianness_for_int_types!(DATE_AND_TIME, u32); +define_endianness_for_int_types!(LDATE, i64); +define_endianness_for_int_types!(LTIME_OF_DAY, i64); +define_endianness_for_int_types!(LDATE_AND_TIME, i64); /// . /// Converts given f32 from native endian data format to big endian data format diff --git a/libs/stdlib/src/extra_functions.rs b/libs/stdlib/src/extra_functions.rs index be9b6d4a525..45543d3c945 100644 --- a/libs/stdlib/src/extra_functions.rs +++ b/libs/stdlib/src/extra_functions.rs @@ -15,6 +15,8 @@ use std::{io::Write, str::FromStr}; // can't determine string buffer length of an empty string, therefore // _TO_STRING functions use the default string length. const DEFAULT_STRING_LEN: usize = 81; +const NANOS_PER_MILLISECOND: i64 = 1_000 * 1_000; +const NANOS_PER_SECOND: i64 = 1_000 * NANOS_PER_MILLISECOND; // --------- x_TO_STRING /// # Safety @@ -170,34 +172,43 @@ pub unsafe extern "C-unwind" fn STRING_TO_REAL(src: *const u8) -> f32 { #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn TIME() -> i64 { +pub extern "C" fn TIME() -> u32 { let dt = Local::now(); - dt.num_seconds_from_midnight() as i64 * 1e9 as i64 + dt.nanosecond() as i64 + dt.num_seconds_from_midnight() * 1_000 + (dt.nanosecond() / NANOS_PER_MILLISECOND as u32) } #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn LTIME() -> i64 { - // LTIME is the same as TIME in RuSTy which we treat as an alias for compatibility with IEC 61131-3 - // See: https://plc-lang.github.io/rusty/datatypes.html#overview-2 - TIME() + let dt = Local::now(); + dt.num_seconds_from_midnight() as i64 * NANOS_PER_SECOND + dt.nanosecond() as i64 +} + +/// # Safety +/// Uses raw pointers, inherently unsafe. +#[allow(non_snake_case)] +#[no_mangle] +pub unsafe extern "C" fn TIME_TO_STRING(dest: *mut u8, input: i32) { + write_time_to_string((input as u32 as i64) * NANOS_PER_MILLISECOND, dest); } /// # Safety /// Uses raw pointers, inherently unsafe. #[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn TIME_TO_STRING_EXT(input: i64, dest: *mut u8) -> i32 { +pub unsafe extern "C" fn LTIME_TO_STRING(dest: *mut u8, input: i64) { + write_time_to_string(input, dest); +} + +unsafe fn write_time_to_string(input_nanos: i64, dest: *mut u8) { let mut dest = dest; - let literals = parse_timestamp(input); + let literals = parse_timestamp(input_nanos); literals.iter().filter(|&it| it.0 != 0).for_each(|it| { let buf = core::slice::from_raw_parts_mut(dest, DEFAULT_STRING_LEN); write!(&mut *buf, "{}{}", it.0, it.1).unwrap(); let idx = buf.iter().position(|&c| c == 0).unwrap(); dest = dest.add(idx); }); - - 0 } fn parse_timestamp<'a>(timestamp_nanos: i64) -> [(u32, &'a str); 7] { @@ -220,43 +231,73 @@ fn parse_timestamp<'a>(timestamp_nanos: i64) -> [(u32, &'a str); 7] { /// Uses raw pointers, inherently unsafe. #[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn DT_TO_STRING_EXT(input: i64, dest: *mut u8) -> i32 { - let datetime = chrono::Utc.timestamp_nanos(input); +pub unsafe extern "C" fn DT_TO_STRING(dest: *mut u8, input: i32) { + write_dt_to_string((input as u32 as i64) * NANOS_PER_SECOND, dest); +} + +/// # Safety +/// Uses raw pointers, inherently unsafe. +#[allow(non_snake_case)] +#[no_mangle] +pub unsafe extern "C" fn LDT_TO_STRING(dest: *mut u8, input: i64) { + write_dt_to_string(input, dest); +} + +unsafe fn write_dt_to_string(input_nanos: i64, dest: *mut u8) { + let datetime = chrono::Utc.timestamp_nanos(input_nanos); let date = datetime.date_naive().to_string(); let time = datetime.time().to_string(); let buf = core::slice::from_raw_parts_mut(dest, DEFAULT_STRING_LEN); write!(&mut *buf, "{date}-{time}").unwrap(); +} - 0 +/// # Safety +/// Uses raw pointers, inherently unsafe. +#[allow(non_snake_case)] +#[no_mangle] +pub unsafe extern "C" fn DATE_TO_STRING(dest: *mut u8, input: i32) { + write_date_to_string((input as u32 as i64) * NANOS_PER_SECOND, dest); } /// # Safety /// Uses raw pointers, inherently unsafe. #[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn DATE_TO_STRING_EXT(input: i64, dest: *mut u8) -> i32 { - let datetime = chrono::Utc.timestamp_nanos(input).date_naive(); +pub unsafe extern "C" fn LDATE_TO_STRING(dest: *mut u8, input: i64) { + write_date_to_string(input, dest); +} + +unsafe fn write_date_to_string(input_nanos: i64, dest: *mut u8) { + let datetime = chrono::Utc.timestamp_nanos(input_nanos).date_naive(); let date = datetime.to_string(); let buf = core::slice::from_raw_parts_mut(dest, DEFAULT_STRING_LEN); write!(&mut *buf, "{date}").unwrap(); +} - 0 +/// # Safety +/// Uses raw pointers, inherently unsafe. +#[allow(non_snake_case)] +#[no_mangle] +pub unsafe extern "C" fn TOD_TO_STRING(dest: *mut u8, input: i32) { + write_tod_to_string((input as u32 as i64) * NANOS_PER_MILLISECOND, dest); } /// # Safety /// Uses raw pointers, inherently unsafe. #[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn TOD_TO_STRING_EXT(input: i64, dest: *mut u8) -> i32 { - let datetime = chrono::Utc.timestamp_nanos(input); +pub unsafe extern "C" fn LTOD_TO_STRING(dest: *mut u8, input: i64) { + write_tod_to_string(input, dest); +} + +unsafe fn write_tod_to_string(input_nanos: i64, dest: *mut u8) { + let datetime = chrono::Utc.timestamp_nanos(input_nanos); let time = datetime.time().to_string(); let buf = core::slice::from_raw_parts_mut(dest, DEFAULT_STRING_LEN); write!(&mut *buf, "{time}").unwrap(); - - 0 } #[cfg(test)] @@ -466,7 +507,7 @@ mod test { let mut dest = [0_u8; 81]; let dest_ptr = dest.as_mut_ptr(); - let _ = unsafe { DATE_TO_STRING_EXT(timestamp, dest_ptr) }; + unsafe { LDATE_TO_STRING(dest_ptr, timestamp) }; let expected = "1982-12-15"; let res = std::str::from_utf8(unsafe { core::slice::from_raw_parts(dest_ptr, 81) }).unwrap(); @@ -483,7 +524,7 @@ mod test { let mut dest = [0_u8; 81]; let dest_ptr = dest.as_mut_ptr(); - let _ = unsafe { DT_TO_STRING_EXT(timestamp, dest_ptr) }; + unsafe { LDT_TO_STRING(dest_ptr, timestamp) }; let expected = "1982-12-15-10:10:02.123456789"; let res = std::str::from_utf8(unsafe { core::slice::from_raw_parts(dest_ptr, 81) }).unwrap(); @@ -500,7 +541,7 @@ mod test { let mut dest = [0_u8; 81]; let dest_ptr = dest.as_mut_ptr(); - let _ = unsafe { TOD_TO_STRING_EXT(timestamp, dest_ptr) }; + unsafe { LTOD_TO_STRING(dest_ptr, timestamp) }; let expected = "10:10:02.123456789"; let res = std::str::from_utf8(unsafe { core::slice::from_raw_parts(dest_ptr, 81) }).unwrap(); @@ -517,7 +558,7 @@ mod test { let mut dest = [0_u8; 81]; let dest_ptr = dest.as_mut_ptr(); - let _ = unsafe { TIME_TO_STRING_EXT(timestamp, dest_ptr) }; + unsafe { LTIME_TO_STRING(dest_ptr, timestamp) }; let expected = "19380d10h10m123ms456us789ns"; let res = std::str::from_utf8(unsafe { core::slice::from_raw_parts(dest_ptr, 81) }).unwrap(); diff --git a/libs/stdlib/src/timers.rs b/libs/stdlib/src/timers.rs index 541aa6ec3cb..767e1cb2f8c 100644 --- a/libs/stdlib/src/timers.rs +++ b/libs/stdlib/src/timers.rs @@ -10,7 +10,8 @@ use crate::utils::Signal; #[cfg(feature = "mock_time")] pub mod test_time_helpers; -pub type Time = i64; +pub type Time = u32; +pub type LTime = i64; #[repr(C)] #[derive(Debug, Default)] @@ -25,10 +26,20 @@ pub struct TimerParams { start_time: Option, } +#[repr(C)] +#[derive(Debug, Default)] +pub struct TimerParamsLTime { + __vtable: usize, + input: bool, + preset_time: LTime, + output: bool, + elapsed_time: LTime, + input_edge: Signal, + is_running: bool, + start_time: Option, +} + impl TimerParams { - /// This method returns true if the timer has already started - /// It does not take into consideration the preset/range for the timer - /// Only if a start time has been set. fn is_running(&self) -> bool { self.is_running } @@ -45,11 +56,63 @@ impl TimerParams { self.set_elapsed_time(0); } - fn set_elapsed_time(&mut self, duration: i64) { + fn set_elapsed_time(&mut self, duration: Time) { + self.elapsed_time = duration; + } + + fn update_elapsed_time(&mut self) { + if self.is_running() { + let elapsed_millis = + self.get_run_time().expect("Timer should be running").as_millis().min(u32::MAX as u128) + as u32; + + self.set_elapsed_time(std::cmp::min(self.preset_time, elapsed_millis)); + } + } + + fn is_in_preset_range(&self) -> bool { + let duration = Duration::from_millis(self.preset_time as u64); + self.get_run_time().is_some_and(|it| it <= duration) + } + + fn get_run_time(&self) -> Option { + self.start_time.map(|it| it.elapsed()) + } + + fn set_output(&mut self, value: bool) { + self.output = value; + } + + fn input_rising_edge(&mut self) -> bool { + self.input_edge.rising_edge(self.input) + } + + fn input_falling_edge(&mut self) -> bool { + self.input_edge.falling_edge(self.input) + } +} + +impl TimerParamsLTime { + fn is_running(&self) -> bool { + self.is_running + } + + fn start(&mut self) { + self.start_time = Some(Instant::now()); + self.is_running = true; + self.set_elapsed_time(0); + } + + fn reset(&mut self) { + self.start_time = None; + self.is_running = false; + self.set_elapsed_time(0); + } + + fn set_elapsed_time(&mut self, duration: LTime) { self.elapsed_time = duration; } - /// Sets the elapsed time to either the preset time or the real elapsed time, whatever is smaller fn update_elapsed_time(&mut self) { if self.is_running() { self.set_elapsed_time(std::cmp::min( @@ -81,13 +144,106 @@ impl TimerParams { } } -#[allow(non_snake_case)] -#[no_mangle] -pub extern "C" fn TP(timer: &mut TimerParams) { - // If timer is active (start time set) +trait TimerLogic { + fn input(&self) -> bool; + fn is_running(&self) -> bool; + fn start(&mut self); + fn reset(&mut self); + fn update_elapsed_time(&mut self); + fn is_in_preset_range(&self) -> bool; + fn set_output(&mut self, value: bool); + fn input_rising_edge(&mut self) -> bool; + fn input_falling_edge(&mut self) -> bool; + fn update_input_edge(&mut self); +} + +impl TimerLogic for TimerParams { + fn input(&self) -> bool { + self.input + } + + fn is_running(&self) -> bool { + self.is_running() + } + + fn start(&mut self) { + self.start() + } + + fn reset(&mut self) { + self.reset() + } + + fn update_elapsed_time(&mut self) { + self.update_elapsed_time() + } + + fn is_in_preset_range(&self) -> bool { + self.is_in_preset_range() + } + + fn set_output(&mut self, value: bool) { + self.set_output(value) + } + + fn input_rising_edge(&mut self) -> bool { + self.input_rising_edge() + } + + fn input_falling_edge(&mut self) -> bool { + self.input_falling_edge() + } + + fn update_input_edge(&mut self) { + self.input_edge.set(self.input); + } +} + +impl TimerLogic for TimerParamsLTime { + fn input(&self) -> bool { + self.input + } + + fn is_running(&self) -> bool { + self.is_running() + } + + fn start(&mut self) { + self.start() + } + + fn reset(&mut self) { + self.reset() + } + + fn update_elapsed_time(&mut self) { + self.update_elapsed_time() + } + + fn is_in_preset_range(&self) -> bool { + self.is_in_preset_range() + } + + fn set_output(&mut self, value: bool) { + self.set_output(value) + } + + fn input_rising_edge(&mut self) -> bool { + self.input_rising_edge() + } + + fn input_falling_edge(&mut self) -> bool { + self.input_falling_edge() + } + + fn update_input_edge(&mut self) { + self.input_edge.set(self.input); + } +} + +fn run_tp(timer: &mut T) { let output = if timer.is_running() { timer.update_elapsed_time(); - // If time elapsed within range if timer.is_in_preset_range() { true } else { @@ -100,43 +256,33 @@ pub extern "C" fn TP(timer: &mut TimerParams) { timer.start(); true } else { - // Behaviour here should be to return only defaults false }; timer.set_output(output); - timer.input_edge.set(timer.input); + timer.update_input_edge(); } -#[allow(non_snake_case)] -#[no_mangle] -pub extern "C" fn TON(timer: &mut TimerParams) { - let output = if timer.input { - //Timer was strarted at some point +fn run_ton(timer: &mut T) { + let output = if timer.input() { if timer.is_running() { - //Timer is still running timer.update_elapsed_time(); !timer.is_in_preset_range() - //Timer stopped, but the input is new } else if timer.input_rising_edge() { timer.start(); false - //Timer stopped, input didn't change (still true from last time) } else { true } } else { - //Input is false, stop timer regardless timer.reset(); false }; timer.set_output(output); - timer.input_edge.set(timer.input); + timer.update_input_edge(); } -#[allow(non_snake_case)] -#[no_mangle] -pub extern "C" fn TOF(timer: &mut TimerParams) { - let output = if timer.input { +fn run_tof(timer: &mut T) { + let output = if timer.input() { if timer.input_rising_edge() { timer.reset(); } @@ -151,41 +297,58 @@ pub extern "C" fn TOF(timer: &mut TimerParams) { false }; timer.set_output(output); - timer.input_edge.set(timer.input); + timer.update_input_edge(); +} + +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn TP(timer: &mut TimerParams) { + TP_TIME(timer) +} + +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn TON(timer: &mut TimerParams) { + TON_TIME(timer) +} + +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn TOF(timer: &mut TimerParams) { + TOF_TIME(timer) } -// Aliases #[no_mangle] pub extern "C" fn TP_TIME(timer: &mut TimerParams) { - TP(timer) + run_tp(timer) } #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn TP_LTIME(timer: &mut TimerParams) { - TP(timer) +pub extern "C" fn TP_LTIME(timer: &mut TimerParamsLTime) { + run_tp(timer) } #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn TON_TIME(timer: &mut TimerParams) { - TON(timer) + run_ton(timer) } #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn TON_LTIME(timer: &mut TimerParams) { - TON(timer) +pub extern "C" fn TON_LTIME(timer: &mut TimerParamsLTime) { + run_ton(timer) } #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn TOF_TIME(timer: &mut TimerParams) { - TOF(timer) + run_tof(timer) } #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn TOF_LTIME(timer: &mut TimerParams) { - TOF(timer) +pub extern "C" fn TOF_LTIME(timer: &mut TimerParamsLTime) { + run_tof(timer) } diff --git a/libs/stdlib/src/types.rs b/libs/stdlib/src/types.rs index 9a32939a153..045f67522d4 100644 --- a/libs/stdlib/src/types.rs +++ b/libs/stdlib/src/types.rs @@ -115,10 +115,14 @@ define_int_type!(MAX__DINT, MIN__DINT, LIMIT__DINT, i32); define_int_type!(MAX__UDINT, MIN__UDINT, LIMIT__UDINT, u32); define_int_type!(MAX__LINT, MIN__LINT, LIMIT__LINT, i64); define_int_type!(MAX__ULINT, MIN__ULINT, LIMIT__ULINT, u64); -define_int_type!(MAX__DATE, MIN__DATE, LIMIT__DATE, i64); -define_int_type!(MAX__DATE_AND_TIME, MIN__DATE_AND_TIME, LIMIT__DATE_AND_TIME, i64); -define_int_type!(MAX__TIME, MIN__TIME, LIMIT__TIME, i64); -define_int_type!(MAX__TIME_OF_DAY, MIN__TIME_OF_DAY, LIMIT__TIME_OF_DAY, i64); +define_int_type!(MAX__DATE, MIN__DATE, LIMIT__DATE, u32); +define_int_type!(MAX__DATE_AND_TIME, MIN__DATE_AND_TIME, LIMIT__DATE_AND_TIME, u32); +define_int_type!(MAX__TIME, MIN__TIME, LIMIT__TIME, u32); +define_int_type!(MAX__TIME_OF_DAY, MIN__TIME_OF_DAY, LIMIT__TIME_OF_DAY, u32); +define_int_type!(MAX__LDATE, MIN__LDATE, LIMIT__LDATE, i64); +define_int_type!(MAX__LDATE_AND_TIME, MIN__LDATE_AND_TIME, LIMIT__LDATE_AND_TIME, i64); +define_int_type!(MAX__LTIME, MIN__LTIME, LIMIT__LTIME, i64); +define_int_type!(MAX__LTIME_OF_DAY, MIN__LTIME_OF_DAY, LIMIT__LTIME_OF_DAY, i64); //Floats define_float_type!(MAX__REAL, MIN__REAL, LIMIT__REAL, f32); define_float_type!(MAX__LREAL, MIN__LREAL, LIMIT__LREAL, f64); diff --git a/libs/stdlib/tests/date_time_conversion_tests.rs b/libs/stdlib/tests/date_time_conversion_tests.rs index e9487364e20..2900507ea55 100644 --- a/libs/stdlib/tests/date_time_conversion_tests.rs +++ b/libs/stdlib/tests/date_time_conversion_tests.rs @@ -24,8 +24,8 @@ fn ltime_to_time_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); - assert_eq!(res, 10000000000); + let res: u32 = compile_and_run(sources, includes, &mut maintype); + assert_eq!(res, 10000); } #[test] @@ -50,7 +50,7 @@ fn ldt_to_dt_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); + let res: u32 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, chrono::NaiveDate::from_ymd_opt(2021, 4, 20) @@ -58,8 +58,7 @@ fn ldt_to_dt_conversion() { .and_hms_opt(22, 33, 14) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap() + .timestamp() as u32 ); } @@ -72,7 +71,7 @@ fn ldt_to_date_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); + let res: u32 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, chrono::NaiveDate::from_ymd_opt(2000, 1, 1) @@ -80,8 +79,7 @@ fn ldt_to_date_conversion() { .and_hms_opt(0, 0, 0) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap() + .timestamp() as u32 ); } @@ -116,7 +114,7 @@ fn ldt_to_tod_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); + let res: u32 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, chrono::NaiveDate::from_ymd_opt(1970, 1, 1) @@ -124,8 +122,7 @@ fn ldt_to_tod_conversion() { .and_hms_milli_opt(20, 15, 11, 543) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap() + .timestamp_millis() as u32 ); } @@ -160,6 +157,27 @@ fn dt_to_date_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); + let res: u32 = compile_and_run(sources, includes, &mut maintype); + assert_eq!( + res, + chrono::NaiveDate::from_ymd_opt(2000, 1, 1) + .unwrap() + .and_hms_opt(0, 0, 0) + .unwrap() + .and_utc() + .timestamp() as u32 + ); +} + +#[test] +fn dt_to_ldate_conversion() { + let src = " + FUNCTION main : LDATE + main := DT_TO_LDATE(DT#2000-01-01-20:15:11); + END_FUNCTION"; + let sources = vec![src.into()]; + let includes = get_includes(&["date_time_conversion.st"]); + let mut maintype = MainType::default(); let res: i64 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, @@ -187,7 +205,7 @@ fn dt_to_ltod_conversion() { res, chrono::NaiveDate::from_ymd_opt(1970, 1, 1) .unwrap() - .and_hms_milli_opt(15, 36, 30, 123) + .and_hms_opt(15, 36, 30) .unwrap() .and_utc() .timestamp_nanos_opt() @@ -204,16 +222,17 @@ fn dt_to_tod_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); + let res: u32 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, - chrono::NaiveDate::from_ymd_opt(1970, 1, 1) + chrono::NaiveDate::from_ymd_opt(2120, 2, 12) .unwrap() - .and_hms_milli_opt(20, 15, 11, 543) + .and_hms_opt(20, 15, 11) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap() + .timestamp() as u32 + % 86_400 + * 1000 ); } @@ -226,7 +245,7 @@ fn ltod_to_tod_conversion() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_conversion.st"]); let mut maintype = MainType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); + let res: u32 = compile_and_run(sources, includes, &mut maintype); assert_eq!( res, chrono::NaiveDate::from_ymd_opt(1970, 1, 1) @@ -234,8 +253,7 @@ fn ltod_to_tod_conversion() { .and_hms_opt(10, 20, 30) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap() + .timestamp_millis() as u32 ); } diff --git a/libs/stdlib/tests/date_time_extra_functions_tests.rs b/libs/stdlib/tests/date_time_extra_functions_tests.rs index a857d653ee1..9a3f5fbc0c3 100644 --- a/libs/stdlib/tests/date_time_extra_functions_tests.rs +++ b/libs/stdlib/tests/date_time_extra_functions_tests.rs @@ -28,15 +28,14 @@ fn concat_date_tod() { let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); let mut maintype = SingleType::default(); - let res: i64 = compile_and_run(sources, includes, &mut maintype); - let dt_2010y_3m_12d_12h_30m_15s_121121121ns = chrono::NaiveDate::from_ymd_opt(2010, 3, 12) + let res: u32 = compile_and_run(sources, includes, &mut maintype); + let dt_2010y_3m_12d_12h_30m_15s = chrono::NaiveDate::from_ymd_opt(2010, 3, 12) .unwrap() - .and_hms_nano_opt(12, 30, 15, 121121121) + .and_hms_opt(12, 30, 15) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap(); - assert_eq!(res, dt_2010y_3m_12d_12h_30m_15s_121121121ns); + .timestamp() as u32; + assert_eq!(res, dt_2010y_3m_12d_12h_30m_15s); } #[test] @@ -85,15 +84,14 @@ fn concat_date_signed_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); let date_2000y_1m_1d = chrono::NaiveDate::from_ymd_opt(2000, 1, 1) .unwrap() .and_hms_opt(0, 0, 0) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap(); + .timestamp() as u32; assert_eq!(maintype.a, date_2000y_1m_1d); assert_eq!(maintype.b, date_2000y_1m_1d); assert_eq!(maintype.c, date_2000y_1m_1d); @@ -114,15 +112,14 @@ fn concat_date_unsigned_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); let date_2000y_1m_1d = chrono::NaiveDate::from_ymd_opt(2000, 1, 1) .unwrap() .and_hms_opt(0, 0, 0) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap(); + .timestamp() as u32; assert_eq!(maintype.a, date_2000y_1m_1d); assert_eq!(maintype.b, date_2000y_1m_1d); assert_eq!(maintype.c, date_2000y_1m_1d); @@ -145,11 +142,10 @@ fn concat_tod_signed_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); - assert_eq!(maintype.a, get_time_from_hms_milli(20, 15, 12, 34).and_utc().timestamp_nanos_opt().unwrap()); - let tod_20h_15m_12s_341ms = - get_time_from_hms_milli(20, 15, 12, 341).and_utc().timestamp_nanos_opt().unwrap(); + assert_eq!(maintype.a, get_time_from_hms_milli(20, 15, 12, 34).and_utc().timestamp_millis() as u32); + let tod_20h_15m_12s_341ms = get_time_from_hms_milli(20, 15, 12, 341).and_utc().timestamp_millis() as u32; assert_eq!(maintype.b, tod_20h_15m_12s_341ms); assert_eq!(maintype.c, tod_20h_15m_12s_341ms); assert_eq!(maintype.d, tod_20h_15m_12s_341ms); @@ -172,11 +168,10 @@ fn concat_tod_unsigned_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); - assert_eq!(maintype.a, get_time_from_hms_milli(20, 15, 12, 34).and_utc().timestamp_nanos_opt().unwrap()); - let tod_20h_15m_12s_341ms = - get_time_from_hms_milli(20, 15, 12, 341).and_utc().timestamp_nanos_opt().unwrap(); + assert_eq!(maintype.a, get_time_from_hms_milli(20, 15, 12, 34).and_utc().timestamp_millis() as u32); + let tod_20h_15m_12s_341ms = get_time_from_hms_milli(20, 15, 12, 341).and_utc().timestamp_millis() as u32; assert_eq!(maintype.b, tod_20h_15m_12s_341ms); assert_eq!(maintype.c, tod_20h_15m_12s_341ms); assert_eq!(maintype.d, tod_20h_15m_12s_341ms); @@ -187,10 +182,10 @@ fn concat_ltod_signed_ints() { let src = " PROGRAM main VAR - a : TOD; - b : TOD; - c : TOD; - d : TOD; + a : LTOD; + b : LTOD; + c : LTOD; + d : LTOD; END_VAR a := CONCAT_LTOD(SINT#20,SINT#15,SINT#12,SINT#34); b := CONCAT_LTOD(INT#20,INT#15,INT#12,INT#341); @@ -214,10 +209,10 @@ fn concat_ltod_unsigned_ints() { let src = " PROGRAM main VAR - a : TOD; - b : TOD; - c : TOD; - d : TOD; + a : LTOD; + b : LTOD; + c : LTOD; + d : LTOD; END_VAR a := CONCAT_LTOD(USINT#20,USINT#15,USINT#12,USINT#34); b := CONCAT_LTOD(UINT#20,UINT#15,UINT#12,UINT#341); @@ -251,18 +246,17 @@ fn concat_dt_signed_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); - let dt_2000y_1m_2d_20h_15m_12s_111ms = chrono::NaiveDate::from_ymd_opt(2000, 1, 2) + let dt_2000y_1m_2d_20h_15m_12s = chrono::NaiveDate::from_ymd_opt(2000, 1, 2) .unwrap() - .and_hms_milli_opt(20, 15, 12, 111) + .and_hms_opt(20, 15, 12) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap(); - assert_eq!(maintype.a, dt_2000y_1m_2d_20h_15m_12s_111ms); - assert_eq!(maintype.b, dt_2000y_1m_2d_20h_15m_12s_111ms); - assert_eq!(maintype.c, dt_2000y_1m_2d_20h_15m_12s_111ms); + .timestamp() as u32; + assert_eq!(maintype.a, dt_2000y_1m_2d_20h_15m_12s); + assert_eq!(maintype.b, dt_2000y_1m_2d_20h_15m_12s); + assert_eq!(maintype.c, dt_2000y_1m_2d_20h_15m_12s); } #[test] @@ -280,18 +274,17 @@ fn concat_dt_unsigned_ints() { END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); - let mut maintype = MainType::::default(); + let mut maintype = MainType::::default(); let _: i64 = compile_and_run(sources, includes, &mut maintype); - let dt_2000y_1m_2d_20h_15m_12s_111ms = chrono::NaiveDate::from_ymd_opt(2000, 1, 2) + let dt_2000y_1m_2d_20h_15m_12s = chrono::NaiveDate::from_ymd_opt(2000, 1, 2) .unwrap() - .and_hms_milli_opt(20, 15, 12, 111) + .and_hms_opt(20, 15, 12) .unwrap() .and_utc() - .timestamp_nanos_opt() - .unwrap(); - assert_eq!(maintype.a, dt_2000y_1m_2d_20h_15m_12s_111ms); - assert_eq!(maintype.b, dt_2000y_1m_2d_20h_15m_12s_111ms); - assert_eq!(maintype.c, dt_2000y_1m_2d_20h_15m_12s_111ms); + .timestamp() as u32; + assert_eq!(maintype.a, dt_2000y_1m_2d_20h_15m_12s); + assert_eq!(maintype.b, dt_2000y_1m_2d_20h_15m_12s); + assert_eq!(maintype.c, dt_2000y_1m_2d_20h_15m_12s); } #[test] @@ -614,7 +607,7 @@ fn split_ltod_int() { c : INT; // second d : INT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -636,7 +629,7 @@ fn split_ltod_uint() { c : UINT; // second d : UINT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -658,7 +651,7 @@ fn split_ltod_dint() { c : DINT; // second d : DINT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -680,7 +673,7 @@ fn split_ltod_udint() { c : UDINT; // second d : UDINT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -702,7 +695,7 @@ fn split_ltod_lint() { c : LINT; // second d : LINT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -724,7 +717,7 @@ fn split_ltod_ulint() { c : ULINT; // second d : ULINT; // millisecond END_VAR - SPLIT_TOD(LTOD#14:12:03.123, a, b, c, d); + SPLIT_LTOD(LTOD#14:12:03.123, a, b, c, d); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -761,7 +754,7 @@ fn split_dt_int() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -789,7 +782,7 @@ fn split_dt_uint() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -817,7 +810,7 @@ fn split_dt_dint() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -845,7 +838,7 @@ fn split_dt_udint() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -873,7 +866,7 @@ fn split_dt_lint() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -901,7 +894,7 @@ fn split_dt_ulint() { assert_eq!(maintype.d, 14); // hour assert_eq!(maintype.e, 12); // minute assert_eq!(maintype.f, 3); // second - assert_eq!(maintype.g, 123); // millisecond + assert_eq!(maintype.g, 0); // millisecond } #[test] @@ -917,7 +910,7 @@ fn split_ldt_int() { f : INT; // second g : INT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -945,7 +938,7 @@ fn split_ldt_uint() { f : UINT; // second g : UINT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -973,7 +966,7 @@ fn split_ldt_dint() { f : DINT; // second g : DINT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -1001,7 +994,7 @@ fn split_ldt_udint() { f : UDINT; // second g : UDINT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -1029,7 +1022,7 @@ fn split_ldt_lint() { f : LINT; // second g : LINT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); @@ -1057,7 +1050,7 @@ fn split_ldt_ulint() { f : ULINT; // second g : ULINT; // millisecond END_VAR - SPLIT_DT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); + SPLIT_LDT(LDT#2000-01-02-14:12:03.123, a, b, c, d, e, f, g); END_PROGRAM"; let sources = vec![src.into()]; let includes = get_includes(&["date_time_extra_functions.st"]); diff --git a/libs/stdlib/tests/date_time_numeric_functions_tests.rs b/libs/stdlib/tests/date_time_numeric_functions_tests.rs index a9c59b85620..433a2b2d660 100644 --- a/libs/stdlib/tests/date_time_numeric_functions_tests.rs +++ b/libs/stdlib/tests/date_time_numeric_functions_tests.rs @@ -1,6 +1,7 @@ use chrono::DurationRound; use chrono::TimeZone; use common::{compile_and_run, get_includes}; +use iec61131std::date_time_numeric_functions as dtf; // Import common functionality into the integration tests mod common; @@ -15,6 +16,16 @@ struct MainType { d: i64, } +#[allow(dead_code)] +#[derive(Default)] +#[repr(C)] +struct ShortMainType { + a: u32, + b: u32, + c: u32, + d: u32, +} + fn get_time_from_hms(hour: u32, min: u32, sec: u32) -> chrono::NaiveDateTime { chrono::NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_opt(hour, min, sec).unwrap() } @@ -23,6 +34,10 @@ fn get_time_from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> chrono: chrono::NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(hour, min, sec, milli).unwrap() } +fn millis_from_hms(hour: u32, min: u32, sec: u32) -> u32 { + ((hour * 60 * 60) + (min * 60) + sec) * 1_000 +} + #[test] fn add_time() { let src = " @@ -30,11 +45,259 @@ fn add_time() { VAR a : TIME; b : TIME; + c : TIME; + d : TIME; + END_VAR + a := ADD(TIME#5s, TIME#30s); + b := ADD_TIME(TIME#10s, TIME#5s); + c := ADD(TIME#250ms, TIME#750ms); + d := ADD_TIME(TIME#1m, TIME#1s); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, 35_000); + assert_eq!(maintype.b, 15_000); + assert_eq!(maintype.c, 1_000); + assert_eq!(maintype.d, 61_000); +} + +#[test] +fn add_tod_time() { + let src = " + PROGRAM main + VAR + a : TOD; + b : TOD; + c : TOD; + d : TOD; + END_VAR + a := ADD(TOD#20:00:00, TIME#1s); + b := ADD_TOD_TIME(TOD#20:00:02, TIME#1s); + c := ADD(TOD#23:59:59, TIME#2s); + d := ADD_TOD_TIME(TOD#12:00:00, TIME#12m12s); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, millis_from_hms(20, 0, 1)); + assert_eq!(maintype.b, millis_from_hms(20, 0, 3)); + assert_eq!(maintype.c, 1_000); + assert_eq!(maintype.d, millis_from_hms(12, 12, 12)); +} + +#[test] +fn add_dt_time() { + let src = " + PROGRAM main + VAR + a : DT; + b : DT; + c : DT; + d : DT; + END_VAR + a := ADD(DT#2000-01-01-12:00:00, TIME#1d12m12s123ms); + b := ADD_DT_TIME(DT#2000-01-01-12:00:00, TIME#1d12m12s123ms); + c := ADD(DT#1970-01-01-00:00:00, TIME#1s); + d := ADD_DT_TIME(DT#1970-01-01-00:00:00, TIME#1500ms); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + let expected = chrono::NaiveDate::from_ymd_opt(2000, 1, 2) + .unwrap() + .and_hms_opt(12, 12, 12) + .unwrap() + .and_utc() + .timestamp() as u32; + + assert_eq!(maintype.a, expected); + assert_eq!(maintype.b, expected); + assert_eq!(maintype.c, 1); + assert_eq!(maintype.d, 1); +} + +#[test] +fn sub_time() { + let src = " + PROGRAM main + VAR + a : TIME; + b : TIME; + c : TIME; + d : TIME; + END_VAR + a := SUB(TIME#10s50ms, TIME#50ms); + b := SUB_TIME(TIME#5m35s20ms, TIME#1m5s20ms); + c := SUB(TIME#10s50ms, TIME#6s20ms); + d := SUB_TIME(TIME#5m35s20ms, TIME#1m5s20ms); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, 10_000); + assert_eq!(maintype.b, 270_000); + assert_eq!(maintype.c, 4_030); + assert_eq!(maintype.d, 270_000); +} + +#[test] +fn sub_date_date() { + let src = " + PROGRAM main + VAR + a : TIME; + b : TIME; + c : TIME; + d : TIME; + END_VAR + a := SUB(DATE#2000-01-21, DATE#2000-01-01); + b := SUB_DATE_DATE(DATE#2000-01-31, DATE#2000-01-01); + c := SUB(DATE#2000-02-10, DATE#2000-01-31); + d := SUB_DATE_DATE(DATE#2000-02-20, DATE#2000-02-10); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, 20 * 24 * 60 * 60 * 1_000); + assert_eq!(maintype.b, 30 * 24 * 60 * 60 * 1_000); + assert_eq!(maintype.c, 10 * 24 * 60 * 60 * 1_000); + assert_eq!(maintype.d, 10 * 24 * 60 * 60 * 1_000); +} + +#[test] +fn sub_tod_time() { + let src = " + PROGRAM main + VAR + a : TOD; + b : TOD; + c : TOD; + d : TOD; + END_VAR + a := SUB(TOD#23:10:05.123, TIME#3h10m5s123ms); + b := SUB_TOD_TIME(TOD#23:10:05.123, TIME#3h10m5s123ms); + c := SUB(TOD#00:00:01.000, TIME#2s); + d := SUB_TOD_TIME(TOD#12:00:00, TIME#12m12s); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, millis_from_hms(20, 0, 0)); + assert_eq!(maintype.b, millis_from_hms(20, 0, 0)); + assert_eq!(maintype.c, millis_from_hms(23, 59, 59)); + assert_eq!(maintype.d, millis_from_hms(11, 47, 48)); +} + +#[test] +fn sub_tod() { + let src = " + PROGRAM main + VAR + a : TIME; + b : TIME; + c : TIME; + d : TIME; + END_VAR + a := SUB(TOD#23:10:05.123, TOD#3:10:05.123); + b := SUB_TOD_TOD(TOD#23:10:05.123, TOD#3:10:05.123); + c := SUB(TOD#10:00:00, TOD#09:59:59); + d := SUB_TOD_TOD(TOD#01:00:00, TOD#00:59:59); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, millis_from_hms(20, 0, 0)); + assert_eq!(maintype.b, millis_from_hms(20, 0, 0)); + assert_eq!(maintype.c, 1_000); + assert_eq!(maintype.d, 1_000); +} + +#[test] +fn sub_dt_time() { + let src = " + PROGRAM main + VAR + a : DT; + b : DT; + c : DT; + d : DT; + END_VAR + a := SUB(DT#2000-01-02-21:15:12.345, TIME#1d1h15m12s345ms); + b := SUB_DT_TIME(DT#2000-01-02-21:15:12.345, TIME#1d1h15m12s345ms); + c := SUB(DT#1970-01-01-00:00:10, TIME#1s); + d := SUB_DT_TIME(DT#1970-01-01-00:00:10, TIME#1500ms); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + let expected = chrono::NaiveDate::from_ymd_opt(2000, 1, 1) + .unwrap() + .and_hms_opt(20, 0, 0) + .unwrap() + .and_utc() + .timestamp() as u32; + + assert_eq!(maintype.a, expected); + assert_eq!(maintype.b, expected); + assert_eq!(maintype.c, 9); + assert_eq!(maintype.d, 9); +} + +#[test] +fn sub_dt() { + let src = " + PROGRAM main + VAR + a : TIME; + b : TIME; + c : TIME; + d : TIME; + END_VAR + a := SUB(DT#1970-01-02-11:22:33, DT#1970-01-01-00:00:00); + b := SUB_DT_DT(DT#1970-01-02-11:22:33, DT#1970-01-01-00:00:00); + c := SUB(DT#1970-01-01-00:00:10, DT#1970-01-01-00:00:00); + d := SUB_DT_DT(DT#1970-01-01-00:00:10, DT#1970-01-01-00:00:00); + END_PROGRAM"; + let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); + let sources = vec![src.into()]; + let mut maintype = ShortMainType::default(); + let _: i64 = compile_and_run(sources, includes, &mut maintype); + + assert_eq!(maintype.a, ((24 + 11) * 60 * 60 + 22 * 60 + 33) * 1_000); + assert_eq!(maintype.b, ((24 + 11) * 60 * 60 + 22 * 60 + 33) * 1_000); + assert_eq!(maintype.c, 10_000); + assert_eq!(maintype.d, 10_000); +} + +#[test] +fn add_ltime() { + let src = " + PROGRAM main + VAR + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := ADD(TIME#5h,TIME#30s); - b := ADD_TIME(TIME#10s,TIME#-5s); + a := ADD(LTIME#5h,LTIME#30s); + b := ADD_LTIME(LTIME#10s,LTIME#-5s); c := ADD(LTIME#-10s,LTIME#-10s); d := ADD_LTIME(LTIME#10s,LTIME#10s); @@ -51,17 +314,17 @@ fn add_time() { } #[test] -fn add_tod_time() { +fn add_ltod_ltime() { let src = " PROGRAM main VAR - a : TOD; - b : TOD; + a : LTOD; + b : LTOD; c : LTOD; d : LTOD; END_VAR - a := ADD_TOD_TIME(TOD#20:00:00, TIME#1s); - b := ADD(TOD#20:00:02, TIME#-1s); + a := ADD_LTOD_LTIME(LTOD#20:00:00, LTIME#1s); + b := ADD(LTOD#20:00:02, LTIME#-1s); c := ADD_LTOD_LTIME(LTOD#12:00:00, LTIME#12m12s); d := ADD(LTOD#12:00:00, LTIME#12m12s); END_PROGRAM"; @@ -78,17 +341,17 @@ fn add_tod_time() { } #[test] -fn add_dt_time() { +fn add_ldt_ltime() { let src = " PROGRAM main VAR - a : DT; - b : DT; + a : LDT; + b : LDT; c : LDT; d : LDT; END_VAR - a := ADD_DT_TIME(DT#2000-01-01-12:00:00, TIME#1d12m12s123ms); - b := ADD(DT#2000-01-01-12:00:00, TIME#1d12m12s123ms); + a := ADD_LDT_LTIME(LDT#2000-01-01-12:00:00, LTIME#1d12m12s123ms); + b := ADD(LDT#2000-01-01-12:00:00, LTIME#1d12m12s123ms); c := ADD_LDT_LTIME(LDT#2000-01-01-12:00:00, LTIME#1d12m12s123ms); d := ADD(LDT#2000-01-01-12:00:00, LTIME#1d12m12s123ms); END_PROGRAM"; @@ -112,17 +375,17 @@ fn add_dt_time() { // add_overflow test moved to tests/lit/single/stdlib_overflow/add_time_overflow.st #[test] -fn sub_time() { +fn sub_ltime() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := SUB(TIME#10h50m, TIME#-10m); - b := SUB_TIME(TIME#5h35m20s, TIME#1h5m20s); + a := SUB(LTIME#10h50m, LTIME#-10m); + b := SUB_LTIME(LTIME#5h35m20s, LTIME#1h5m20s); c := SUB(LTIME#10h50m, LTIME#6h20m); d := SUB_LTIME(LTIME#5h35m20s, LTIME#1h5m20s); @@ -139,17 +402,17 @@ fn sub_time() { } #[test] -fn sub_date() { +fn sub_ldate_ldate() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := SUB(DATE#2000-12-31, DATE#2000-01-01); - b := SUB_DATE_DATE(DATE#2000-05-21, DATE#2000-05-01); + a := SUB(LDATE#2000-12-31, LDATE#2000-01-01); + b := SUB_LDATE_LDATE(LDATE#2000-05-21, LDATE#2000-05-01); c := SUB(LDATE#2000-12-31, LDATE#2000-01-01); d := SUB_LDATE_LDATE(LDATE#2000-05-21, LDATE#2000-05-01); @@ -167,17 +430,17 @@ fn sub_date() { } #[test] -fn sub_tod_time() { +fn sub_ltod_ltime() { let src = " PROGRAM main VAR - a : TOD; - b : TOD; + a : LTOD; + b : LTOD; c : LTOD; d : LTOD; END_VAR - a := SUB_TOD_TIME(TOD#23:10:05.123, TIME#3h10m5s123ms); - b := SUB(TOD#23:10:05.123, TIME#3h10m5s123ms); + a := SUB_LTOD_LTIME(LTOD#23:10:05.123, LTIME#3h10m5s123ms); + b := SUB(LTOD#23:10:05.123, LTIME#3h10m5s123ms); c := SUB_LTOD_LTIME(LTOD#23:10:05.123, LTIME#3h10m5s123ms); d := SUB(LTOD#23:10:05.123, LTIME#3h10m5s123ms); END_PROGRAM"; @@ -193,17 +456,17 @@ fn sub_tod_time() { } #[test] -fn sub_tod() { +fn sub_ltod_ltod() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := SUB(TOD#23:10:05.123, TOD#3:10:05.123); - b := SUB_TOD_TOD(TOD#23:10:05.123, TOD#3:10:05.123); + a := SUB(LTOD#23:10:05.123, LTOD#3:10:05.123); + b := SUB_LTOD_LTOD(LTOD#23:10:05.123, LTOD#3:10:05.123); c := SUB(LTOD#23:10:05.123, LTOD#3:10:05.123); d := SUB_LTOD_LTOD(LTOD#23:10:05.123, LTOD#3:10:05.123); END_PROGRAM"; @@ -219,17 +482,17 @@ fn sub_tod() { } #[test] -fn sub_dt_time() { +fn sub_ldt_ltime() { let src = " PROGRAM main VAR - a : DT; - b : DT; + a : LDT; + b : LDT; c : LDT; d : LDT; END_VAR - a := SUB(DT#2000-01-02-21:15:12.345, TIME#1d1h15m12s345ms); - b := SUB_DT_TIME(DT#2000-01-02-21:15:12.345, TIME#1d1h15m12s345ms); + a := SUB(LDT#2000-01-02-21:15:12.345, LTIME#1d1h15m12s345ms); + b := SUB_LDT_LTIME(LDT#2000-01-02-21:15:12.345, LTIME#1d1h15m12s345ms); c := SUB(LDT#2000-01-02-21:15:12.345, LTIME#1d1h15m12s345ms); d := SUB_LDT_LTIME(LDT#2000-01-02-21:15:12.345, LTIME#1d1h15m12s345ms); END_PROGRAM"; @@ -251,17 +514,17 @@ fn sub_dt_time() { } #[test] -fn sub_dt() { +fn sub_ldt_ldt() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := SUB(DT#2000-01-02-21:22:33.444, DT#2000-01-01-10:00:00.000); - b := SUB_DT_DT(DT#2000-01-02-21:22:33.444, DT#2000-01-01-10:00:00.000); + a := SUB(LDT#2000-01-02-21:22:33.444, LDT#2000-01-01-10:00:00.000); + b := SUB_LDT_LDT(LDT#2000-01-02-21:22:33.444, LDT#2000-01-01-10:00:00.000); c := SUB(LDT#2000-01-02-21:22:33.444, LDT#2000-01-01-10:00:00.000); d := SUB_LDT_LDT(LDT#2000-01-02-21:22:33.444, LDT#2000-01-01-10:00:00.000); END_PROGRAM"; @@ -289,13 +552,13 @@ fn mul_signed() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := MUL(TIME#1d, SINT#-120); - b := MUL(TIME#1s, INT#3600); + a := MUL(LTIME#1d, SINT#-120); + b := MUL(LTIME#1s, INT#3600); c := MUL(LTIME#1000ms, DINT#86400); d := MUL(LTIME#1000ms, LINT#864000000); END_PROGRAM"; @@ -320,13 +583,13 @@ fn mul_unsigned() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := MUL(TIME#-1d, USINT#120); - b := MUL(TIME#1s, UINT#3600); + a := MUL(LTIME#-1d, USINT#120); + b := MUL(LTIME#1s, UINT#3600); c := MUL(LTIME#1000ms, UDINT#86400); d := MUL(LTIME#1000ms, ULINT#864000000); END_PROGRAM"; @@ -350,15 +613,15 @@ fn mul_time_signed() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; - c : TIME; - d : TIME; + a : LTIME; + b : LTIME; + c : LTIME; + d : LTIME; END_VAR - a := MUL_TIME(TIME#1d, SINT#-120); - b := MUL_TIME(TIME#1s, INT#3600); - c := MUL_TIME(TIME#1000ms, DINT#86400); - d := MUL_TIME(TIME#1000ms, LINT#864000000); + a := MUL_LTIME(LTIME#1d, SINT#-120); + b := MUL_LTIME(LTIME#1s, INT#3600); + c := MUL_LTIME(LTIME#1000ms, DINT#86400); + d := MUL_LTIME(LTIME#1000ms, LINT#864000000); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -378,15 +641,15 @@ fn mul_time_unsigned() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; - c : TIME; - d : TIME; + a : LTIME; + b : LTIME; + c : LTIME; + d : LTIME; END_VAR - a := MUL_TIME(TIME#-1d, USINT#120); - b := MUL_TIME(TIME#1s, UINT#3600); - c := MUL_TIME(TIME#1000ms, UDINT#86400); - d := MUL_TIME(TIME#1000ms, ULINT#864000000); + a := MUL_LTIME(LTIME#-1d, USINT#120); + b := MUL_LTIME(LTIME#1s, UINT#3600); + c := MUL_LTIME(LTIME#1000ms, UDINT#86400); + d := MUL_LTIME(LTIME#1000ms, ULINT#864000000); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -462,13 +725,13 @@ fn div_signed() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := DIV(TIME#1m, SINT#60); - b := DIV(TIME#1h, INT#-3600); + a := DIV(LTIME#1m, SINT#60); + b := DIV(LTIME#1h, INT#-3600); c := DIV(LTIME#1d, DINT#86400); d := DIV(LTIME#10000d, DINT#864000000); END_PROGRAM"; @@ -488,13 +751,13 @@ fn div_unsigned() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; c : LTIME; d : LTIME; END_VAR - a := DIV(TIME#1m, USINT#60); - b := DIV(TIME#-1h, UINT#3600); + a := DIV(LTIME#1m, USINT#60); + b := DIV(LTIME#-1h, UINT#3600); c := DIV(LTIME#1d, UDINT#86400); d := DIV(LTIME#10000d, UDINT#864000000); END_PROGRAM"; @@ -516,15 +779,15 @@ fn div_time_signed() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; - c : TIME; - d : TIME; + a : LTIME; + b : LTIME; + c : LTIME; + d : LTIME; END_VAR - a := DIV_TIME(TIME#1m, SINT#60); - b := DIV_TIME(TIME#1h, INT#-3600); - c := DIV_TIME(TIME#1d, DINT#86400); - d := DIV_TIME(TIME#10000d, DINT#864000000); + a := DIV_LTIME(LTIME#1m, SINT#60); + b := DIV_LTIME(LTIME#1h, INT#-3600); + c := DIV_LTIME(LTIME#1d, DINT#86400); + d := DIV_LTIME(LTIME#10000d, DINT#864000000); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -542,15 +805,15 @@ fn div_time_unsigned() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; - c : TIME; - d : TIME; + a : LTIME; + b : LTIME; + c : LTIME; + d : LTIME; END_VAR - a := DIV_TIME(TIME#1m, USINT#60); - b := DIV_TIME(TIME#-1h, UINT#3600); - c := DIV_TIME(TIME#1d, UDINT#86400); - d := DIV_TIME(TIME#10000d, UDINT#864000000); + a := DIV_LTIME(LTIME#1m, USINT#60); + b := DIV_LTIME(LTIME#-1h, UINT#3600); + c := DIV_LTIME(LTIME#1d, UDINT#86400); + d := DIV_LTIME(LTIME#10000d, UDINT#864000000); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -621,13 +884,13 @@ fn mul_real() { let src = " PROGRAM main VAR - a : TIME; + a : LTIME; b : LTIME; - c : TIME; + c : LTIME; END_VAR - a := MUL(TIME#-2s700ms, REAL#3.14); + a := MUL(LTIME#-2s700ms, REAL#3.14); b := MUL(LTIME#2s700ms, REAL#3.14e5); - c := MUL(TIME#2s700ms, REAL#-3.14); + c := MUL(LTIME#2s700ms, REAL#-3.14); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -656,13 +919,13 @@ fn mul_lreal() { let src = " PROGRAM main VAR - a : TIME; + a : LTIME; b : LTIME; - c : TIME; + c : LTIME; END_VAR - a := MUL(TIME#-2s700ms, LREAL#3.14); + a := MUL(LTIME#-2s700ms, LREAL#3.14); b := MUL(LTIME#2s700ms, LREAL#3.14e5); - c := MUL(TIME#-2s700ms, LREAL#-3.14); + c := MUL(LTIME#-2s700ms, LREAL#-3.14); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -698,11 +961,11 @@ fn mul_time() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; END_VAR - a := MUL_TIME(TIME#2s700ms, REAL#3.14); - b := MUL_TIME(TIME#2s700ms, LREAL#3.14e5); + a := MUL_LTIME(LTIME#2s700ms, REAL#3.14); + b := MUL_LTIME(LTIME#2s700ms, LREAL#3.14e5); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -753,10 +1016,10 @@ fn div_real() { let src = " PROGRAM main VAR - a : TIME; + a : LTIME; b : LTIME; END_VAR - a := DIV(TIME#-8s478ms, REAL#3.14); + a := DIV(LTIME#-8s478ms, REAL#3.14); b := DIV(LTIME#847800s, REAL#3.14e5); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); @@ -780,10 +1043,10 @@ fn div_lreal() { let src = " PROGRAM main VAR - a : TIME; + a : LTIME; b : LTIME; END_VAR - a := DIV(TIME#-8s478ms, LREAL#3.14); + a := DIV(LTIME#-8s478ms, LREAL#3.14); b := DIV(LTIME#847800s, LREAL#3.14e5); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); @@ -807,11 +1070,11 @@ fn div_time() { let src = " PROGRAM main VAR - a : TIME; - b : TIME; + a : LTIME; + b : LTIME; END_VAR - a := DIV_TIME(TIME#8s478ms, REAL#3.14); - b := DIV_TIME(TIME#847800s, LREAL#3.14e5); + a := DIV_LTIME(LTIME#8s478ms, REAL#3.14); + b := DIV_LTIME(LTIME#847800s, LREAL#3.14e5); END_PROGRAM"; let includes = get_includes(&["date_time_numeric_functions.st", "arithmetic_functions.st"]); let sources = vec![src.into()]; @@ -858,14 +1121,14 @@ fn date_time_overloaded_add_function_called_with_too_many_params() { let src = " FUNCTION main : LINT // This test should panic because the argument count is incorrect, i.e. `ADD_TIME` is defined as - // FUNCTION ADD_TIME : TIME + // FUNCTION ADD_TIME : LTIME // VAR_INPUT - // IN1: TIME; - // IN2: TIME; + // IN1: LTIME; + // IN2: LTIME; // END_VAR // END_FUNCTION` - ADD(TIME#3h, TIME#2h, TIME#2h, TIME#3h, TIME#30s); + ADD(LTIME#3h, LTIME#2h, LTIME#2h, LTIME#3h, LTIME#30s); END_FUNCTION "; @@ -885,8 +1148,8 @@ fn date_time_overloaded_add_and_numerical_add_compile_correctly() { b: REAL; END_VAR VAR_TEMP - var_tod : TOD := TOD#23:00:01; - var_time : TIME := TIME#55m59s; + var_tod : LTOD := LTOD#23:00:01; + var_time : LTIME := LTIME#55m59s; var_real : REAL := 1.0; var_dint : DINT := 10; END_VAR @@ -910,3 +1173,439 @@ fn date_time_overloaded_add_and_numerical_add_compile_correctly() { assert_eq!(tod_23h_56m, maintype.a); assert_eq!(18.0, maintype.b); } + +macro_rules! panic_i64_i64_tests { + ($(($name:ident, $func:path, $lhs:expr, $rhs:expr)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func($lhs, $rhs); + } + )+ + }; +} + +macro_rules! panic_i64_i8_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_i8); + } + )+ + }; +} + +macro_rules! panic_i64_i16_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_i16); + } + )+ + }; +} + +macro_rules! panic_i64_i32_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_i32); + } + )+ + }; +} + +macro_rules! panic_i64_u8_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_u8); + } + )+ + }; +} + +macro_rules! panic_i64_u16_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_u16); + } + )+ + }; +} + +macro_rules! panic_i64_u32_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_u32); + } + )+ + }; +} + +macro_rules! panic_i64_u64_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2_u64); + } + )+ + }; +} + +macro_rules! panic_i64_f32_mul_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2.0_f32); + } + )+ + }; +} + +macro_rules! panic_i64_f64_mul_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(i64::MAX, 2.0_f64); + } + )+ + }; +} + +macro_rules! panic_i64_i8_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_i8); + } + )+ + }; +} + +macro_rules! panic_i64_i16_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_i16); + } + )+ + }; +} + +macro_rules! panic_i64_i32_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_i32); + } + )+ + }; +} + +macro_rules! panic_i64_i64_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_i64); + } + )+ + }; +} + +macro_rules! panic_i64_u8_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_u8); + } + )+ + }; +} + +macro_rules! panic_i64_u16_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_u16); + } + )+ + }; +} + +macro_rules! panic_i64_u32_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_u32); + } + )+ + }; +} + +macro_rules! panic_i64_u64_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0_u64); + } + )+ + }; +} + +macro_rules! panic_i64_f32_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0.0_f32); + } + )+ + }; +} + +macro_rules! panic_i64_f64_div_zero_tests { + ($(($name:ident, $func:path)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func(1, 0.0_f64); + } + )+ + }; +} + +macro_rules! panic_u32_u32_tests { + ($(($name:ident, $func:path, $lhs:expr, $rhs:expr)),+ $(,)?) => { + $( + #[test] + #[should_panic] + fn $name() { + let _ = $func($lhs, $rhs); + } + )+ + }; +} + +panic_u32_u32_tests!( + (add_time_panics_on_overflow, dtf::ADD_TIME, u32::MAX, 1), + (add_dt_time_panics_on_overflow, dtf::ADD_DT_TIME, u32::MAX, 1_000), + (sub_time_panics_on_underflow, dtf::SUB_TIME, 2_000, 5_000), + (sub_date_date_panics_when_time_difference_exceeds_time_range, dtf::SUB_DATE_DATE, 50 * 24 * 60 * 60, 0), + (sub_tod_tod_panics_on_underflow, dtf::SUB_TOD_TOD, 1_000, 2_000), + (sub_dt_time_panics_on_underflow, dtf::SUB_DT_TIME, 0, 1_000), + (sub_dt_dt_panics_when_time_difference_exceeds_time_range, dtf::SUB_DT_DT, 50 * 24 * 60 * 60, 0) +); + +panic_i64_i64_tests!( + (add_ltime_panics_on_overflow, dtf::ADD_LTIME, i64::MAX, 1), + (add_ltod_ltime_panics_on_overflow, dtf::ADD_LTOD_LTIME, i64::MAX, 1), + (add_ldt_ltime_panics_on_overflow, dtf::ADD_LDT_LTIME, i64::MAX, 1), + (sub_ltime_panics_on_underflow, dtf::SUB_LTIME, i64::MIN, 1), + (sub_ldate_ldate_panics_on_large_delta, dtf::SUB_LDATE_LDATE, i64::MAX, i64::MIN), + (sub_ltod_ltime_panics_on_underflow, dtf::SUB_LTOD_LTIME, i64::MIN, 1), + (sub_ltod_ltod_panics_on_large_delta, dtf::SUB_LTOD_LTOD, i64::MAX, i64::MIN), + (sub_ldt_ltime_panics_on_underflow, dtf::SUB_LDT_LTIME, i64::MIN, 1), + (sub_ldt_ldt_panics_on_large_delta, dtf::SUB_LDT_LDT, i64::MAX, i64::MIN), + (add_alias_ltime_ltime_panics_on_overflow, dtf::ADD__LTIME__LTIME, i64::MAX, 1), + (add_alias_ltod_ltime_panics_on_overflow, dtf::ADD__LTOD__LTIME, i64::MAX, 1), + (add_alias_ldt_ltime_panics_on_overflow, dtf::ADD__LDT__LTIME, i64::MAX, 1), + (sub_alias_ltime_ltime_panics_on_underflow, dtf::SUB__LTIME__LTIME, i64::MIN, 1), + (sub_alias_ldate_ldate_panics_on_large_delta, dtf::SUB__LDATE__LDATE, i64::MAX, i64::MIN), + (sub_alias_ltod_ltime_panics_on_underflow, dtf::SUB__LTOD__LTIME, i64::MIN, 1), + (sub_alias_ltod_ltod_panics_on_large_delta, dtf::SUB__LTOD__LTOD, i64::MAX, i64::MIN), + (sub_alias_ldt_ltime_panics_on_underflow, dtf::SUB__LDT__LTIME, i64::MIN, 1), + (sub_alias_ldt_ldt_panics_on_large_delta, dtf::SUB__LDT__LDT, i64::MAX, i64::MIN), + (add_alias_ldate_and_time_ltime_panics_on_overflow, dtf::ADD__LDATE_AND_TIME__LTIME, i64::MAX, 1), + (add_alias_ltime_of_day_ltime_panics_on_overflow, dtf::ADD__LTIME_OF_DAY__LTIME, i64::MAX, 1), + (sub_alias_ldate_and_time_ltime_panics_on_underflow, dtf::SUB__LDATE_AND_TIME__LTIME, i64::MIN, 1), + ( + sub_alias_ldate_and_time_ldate_and_time_panics_on_large_delta, + dtf::SUB__LDATE_AND_TIME__LDATE_AND_TIME, + i64::MAX, + i64::MIN + ), + (sub_alias_ltime_of_day_ltime_panics_on_underflow, dtf::SUB__LTIME_OF_DAY__LTIME, i64::MIN, 1), + ( + sub_alias_ltime_of_day_ltime_of_day_panics_on_large_delta, + dtf::SUB__LTIME_OF_DAY__LTIME_OF_DAY, + i64::MAX, + i64::MIN + ), + (mul_time_lint_panics_on_overflow, dtf::MUL__TIME__LINT, i64::MAX, 2), + (mul_time_lint_alias_panics_on_overflow, dtf::MUL_TIME__LINT, i64::MAX, 2), + (mul_ltime_lint_panics_on_overflow, dtf::MUL_LTIME__LINT, i64::MAX, 2), + (mul_alias_ltime_lint_panics_on_overflow, dtf::MUL__LTIME__LINT, i64::MAX, 2) +); + +panic_i64_i8_tests!( + (mul_time_sint_panics_on_overflow, dtf::MUL__TIME__SINT), + (mul_time_sint_alias_panics_on_overflow, dtf::MUL_TIME__SINT), + (mul_ltime_sint_panics_on_overflow, dtf::MUL_LTIME__SINT), + (mul_alias_ltime_sint_panics_on_overflow, dtf::MUL__LTIME__SINT) +); + +panic_i64_i16_tests!( + (mul_time_int_panics_on_overflow, dtf::MUL__TIME__INT), + (mul_time_int_alias_panics_on_overflow, dtf::MUL_TIME__INT), + (mul_ltime_int_panics_on_overflow, dtf::MUL_LTIME__INT), + (mul_alias_ltime_int_panics_on_overflow, dtf::MUL__LTIME__INT) +); + +panic_i64_i32_tests!( + (mul_time_dint_panics_on_overflow, dtf::MUL__TIME__DINT), + (mul_time_dint_alias_panics_on_overflow, dtf::MUL_TIME__DINT), + (mul_ltime_dint_panics_on_overflow, dtf::MUL_LTIME__DINT), + (mul_alias_ltime_dint_panics_on_overflow, dtf::MUL__LTIME__DINT) +); + +panic_i64_u8_tests!( + (mul_time_usint_panics_on_overflow, dtf::MUL__TIME__USINT), + (mul_time_usint_alias_panics_on_overflow, dtf::MUL_TIME__USINT), + (mul_ltime_usint_panics_on_overflow, dtf::MUL_LTIME__USINT), + (mul_alias_ltime_usint_panics_on_overflow, dtf::MUL__LTIME__USINT) +); + +panic_i64_u16_tests!( + (mul_time_uint_panics_on_overflow, dtf::MUL__TIME__UINT), + (mul_time_uint_alias_panics_on_overflow, dtf::MUL_TIME__UINT), + (mul_ltime_uint_panics_on_overflow, dtf::MUL_LTIME__UINT), + (mul_alias_ltime_uint_panics_on_overflow, dtf::MUL__LTIME__UINT) +); + +panic_i64_u32_tests!( + (mul_time_udint_panics_on_overflow, dtf::MUL__TIME__UDINT), + (mul_time_udint_alias_panics_on_overflow, dtf::MUL_TIME__UDINT), + (mul_ltime_udint_panics_on_overflow, dtf::MUL_LTIME__UDINT), + (mul_alias_ltime_udint_panics_on_overflow, dtf::MUL__LTIME__UDINT) +); + +panic_i64_u64_tests!( + (mul_time_ulint_panics_on_overflow, dtf::MUL__TIME__ULINT), + (mul_time_ulint_alias_panics_on_overflow, dtf::MUL_TIME__ULINT), + (mul_ltime_ulint_panics_on_overflow, dtf::MUL_LTIME__ULINT), + (mul_alias_ltime_ulint_panics_on_overflow, dtf::MUL__LTIME__ULINT) +); + +panic_i64_f32_mul_tests!( + (mul_time_real_panics_on_overflow, dtf::MUL__TIME__REAL), + (mul_time_real_alias_panics_on_overflow, dtf::MUL_TIME__REAL), + (mul_ltime_real_panics_on_overflow, dtf::MUL_LTIME__REAL), + (mul_alias_ltime_real_panics_on_overflow, dtf::MUL__LTIME__REAL) +); + +panic_i64_f64_mul_tests!( + (mul_time_lreal_panics_on_overflow, dtf::MUL__TIME__LREAL), + (mul_time_lreal_alias_panics_on_overflow, dtf::MUL_TIME__LREAL), + (mul_ltime_lreal_panics_on_overflow, dtf::MUL_LTIME__LREAL), + (mul_alias_ltime_lreal_panics_on_overflow, dtf::MUL__LTIME__LREAL) +); + +panic_i64_i8_div_zero_tests!( + (div_time_sint_panics_on_zero, dtf::DIV__TIME__SINT), + (div_time_sint_alias_panics_on_zero, dtf::DIV_TIME__SINT), + (div_ltime_sint_panics_on_zero, dtf::DIV_LTIME__SINT), + (div_alias_ltime_sint_panics_on_zero, dtf::DIV__LTIME__SINT) +); + +panic_i64_i16_div_zero_tests!( + (div_time_int_panics_on_zero, dtf::DIV__TIME__INT), + (div_time_int_alias_panics_on_zero, dtf::DIV_TIME__INT), + (div_ltime_int_panics_on_zero, dtf::DIV_LTIME__INT), + (div_alias_ltime_int_panics_on_zero, dtf::DIV__LTIME__INT) +); + +panic_i64_i32_div_zero_tests!( + (div_time_dint_panics_on_zero, dtf::DIV__TIME__DINT), + (div_time_dint_alias_panics_on_zero, dtf::DIV_TIME__DINT), + (div_ltime_dint_panics_on_zero, dtf::DIV_LTIME__DINT), + (div_alias_ltime_dint_panics_on_zero, dtf::DIV__LTIME__DINT) +); + +panic_i64_i64_div_zero_tests!( + (div_time_lint_panics_on_zero, dtf::DIV__TIME__LINT), + (div_time_lint_alias_panics_on_zero, dtf::DIV_TIME__LINT), + (div_ltime_lint_panics_on_zero, dtf::DIV_LTIME__LINT), + (div_alias_ltime_lint_panics_on_zero, dtf::DIV__LTIME__LINT) +); + +panic_i64_u8_div_zero_tests!( + (div_time_usint_panics_on_zero, dtf::DIV__TIME__USINT), + (div_time_usint_alias_panics_on_zero, dtf::DIV_TIME__USINT), + (div_ltime_usint_panics_on_zero, dtf::DIV_LTIME__USINT), + (div_alias_ltime_usint_panics_on_zero, dtf::DIV__LTIME__USINT) +); + +panic_i64_u16_div_zero_tests!( + (div_time_uint_panics_on_zero, dtf::DIV__TIME__UINT), + (div_time_uint_alias_panics_on_zero, dtf::DIV_TIME__UINT), + (div_ltime_uint_panics_on_zero, dtf::DIV_LTIME__UINT), + (div_alias_ltime_uint_panics_on_zero, dtf::DIV__LTIME__UINT) +); + +panic_i64_u32_div_zero_tests!( + (div_time_udint_panics_on_zero, dtf::DIV__TIME__UDINT), + (div_time_udint_alias_panics_on_zero, dtf::DIV_TIME__UDINT), + (div_ltime_udint_panics_on_zero, dtf::DIV_LTIME__UDINT), + (div_alias_ltime_udint_panics_on_zero, dtf::DIV__LTIME__UDINT) +); + +panic_i64_u64_div_zero_tests!( + (div_time_ulint_panics_on_zero, dtf::DIV__TIME__ULINT), + (div_time_ulint_alias_panics_on_zero, dtf::DIV_TIME__ULINT), + (div_ltime_ulint_panics_on_zero, dtf::DIV_LTIME__ULINT), + (div_alias_ltime_ulint_panics_on_zero, dtf::DIV__LTIME__ULINT) +); + +panic_i64_f32_div_zero_tests!( + (div_time_real_panics_on_zero, dtf::DIV__TIME__REAL), + (div_time_real_alias_panics_on_zero, dtf::DIV_TIME__REAL), + (div_ltime_real_panics_on_zero, dtf::DIV_LTIME__REAL), + (div_alias_ltime_real_panics_on_zero, dtf::DIV__LTIME__REAL) +); + +panic_i64_f64_div_zero_tests!( + (div_time_lreal_panics_on_zero, dtf::DIV__TIME__LREAL), + (div_time_lreal_alias_panics_on_zero, dtf::DIV_TIME__LREAL), + (div_ltime_lreal_panics_on_zero, dtf::DIV_LTIME__LREAL), + (div_alias_ltime_lreal_panics_on_zero, dtf::DIV__LTIME__LREAL) +); diff --git a/libs/stdlib/tests/endianness_conversion_functions_tests.rs b/libs/stdlib/tests/endianness_conversion_functions_tests.rs index 82a91e32bae..073b087c9d8 100644 --- a/libs/stdlib/tests/endianness_conversion_functions_tests.rs +++ b/libs/stdlib/tests/endianness_conversion_functions_tests.rs @@ -3,8 +3,8 @@ mod common; use crate::common::{compile_and_run_no_params, get_includes}; use chrono::NaiveDate; -const DURATION_MILLIS: i64 = (22 * 3600 + 22 * 60 + 22) * 1000; -const DURATION_NANOS: i64 = DURATION_MILLIS * 1000000; +const DURATION_MILLIS: u32 = (22 * 3600 + 22 * 60 + 22) * 1000; +const DURATION_NANOS: i64 = DURATION_MILLIS as i64 * 1_000_000; ///-------------------------------INT #[test] @@ -651,16 +651,11 @@ fn test_to_big_endian_date() { "#; let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + (NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32) .to_be() ) } @@ -673,16 +668,11 @@ fn test_to_little_endian_date() { "#; let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + (NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32) .to_le() ) } @@ -695,17 +685,12 @@ fn test_from_big_endian_date() { "#; let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - i64::from_be( - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + u32::from_be( + NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32 ) ) } @@ -718,17 +703,12 @@ fn test_from_little_endian_date() { "#; let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - i64::from_le( - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + u32::from_le( + NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32 ) ) } @@ -743,8 +723,8 @@ fn test_to_big_endian_tod() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); - assert_eq!(res, DURATION_NANOS.to_be()) + let res: u32 = compile_and_run_no_params(src, includes); + assert_eq!(res, DURATION_MILLIS.to_be()) } #[test] @@ -756,8 +736,8 @@ fn test_to_little_endian_tod() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); - assert_eq!(res, DURATION_NANOS.to_le()) + let res: u32 = compile_and_run_no_params(src, includes); + assert_eq!(res, DURATION_MILLIS.to_le()) } #[test] @@ -769,8 +749,8 @@ fn test_from_big_endian_tod() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); - assert_eq!(res, i64::from_be(DURATION_NANOS)) + let res: u32 = compile_and_run_no_params(src, includes); + assert_eq!(res, u32::from_be(DURATION_MILLIS)) } #[test] @@ -782,8 +762,8 @@ fn test_from_little_endian_tod() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); - assert_eq!(res, i64::from_le(DURATION_NANOS)) + let res: u32 = compile_and_run_no_params(src, includes); + assert_eq!(res, u32::from_le(DURATION_MILLIS)) } ///-------------------------------DT @@ -796,16 +776,11 @@ fn test_to_big_endian_dt() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + (NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32) .to_be() ) } @@ -819,16 +794,11 @@ fn test_to_little_endian_dt() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + (NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32) .to_le() ) } @@ -842,17 +812,12 @@ fn test_from_big_endian_dt() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - i64::from_be( - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + u32::from_be( + NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32 ) ) } @@ -866,17 +831,12 @@ fn test_from_little_endian_dt() { let src = vec![src.into()]; let includes = get_includes(&["endianness_conversion_functions.st"]); - let res: i64 = compile_and_run_no_params(src, includes); + let res: u32 = compile_and_run_no_params(src, includes); assert_eq!( res, - i64::from_le( - NaiveDate::from_ymd_opt(1984, 6, 25) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap() - .and_utc() - .timestamp_nanos_opt() - .unwrap() + u32::from_le( + NaiveDate::from_ymd_opt(1984, 6, 25).unwrap().and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp() + as u32 ) ) } diff --git a/libs/stdlib/tests/extra_function_tests.rs b/libs/stdlib/tests/extra_function_tests.rs index 5d5943b8672..61613399c09 100644 --- a/libs/stdlib/tests/extra_function_tests.rs +++ b/libs/stdlib/tests/extra_function_tests.rs @@ -486,8 +486,8 @@ fn tod_to_lword_conversion() { ]); let res: u64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(1, 59, 59, 2567e5 as u32).unwrap(); - let expected = time.num_seconds_from_midnight() as u64 * 1e9 as u64 + time.nanosecond() as u64; + let time = NaiveTime::from_hms_milli_opt(1, 59, 59, 256).unwrap(); + let expected = time.num_seconds_from_midnight() as u64 * 1000 + u64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -536,7 +536,7 @@ fn dt_to_lword_conversion() { let date = NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(); let time = NaiveTime::from_hms_micro_opt(1, 59, 59, 256700).unwrap(); - let expected = NaiveDateTime::new(date, time).and_utc().timestamp_nanos_opt().unwrap() as u64; + let expected = NaiveDateTime::new(date, time).and_utc().timestamp() as u64; assert_eq!(expected, res) } @@ -586,7 +586,7 @@ fn date_to_lword_conversion() { let date = NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(); let time = NaiveTime::from_hms_opt(0, 0, 0).unwrap(); - let expected = NaiveDateTime::new(date, time).and_utc().timestamp_nanos_opt().unwrap() as u64; + let expected = NaiveDateTime::new(date, time).and_utc().timestamp() as u64; assert_eq!(expected, res) } @@ -634,8 +634,8 @@ fn time_to_lword_conversion() { ]); let res: u64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(12, 1, 20, 391e6 as u32 + 10).unwrap(); - let expected = time.num_seconds_from_midnight() as u64 * 1e9 as u64 + time.nanosecond() as u64; + let time = NaiveTime::from_hms_milli_opt(12, 1, 20, 391).unwrap(); + let expected = time.num_seconds_from_midnight() as u64 * 1000 + u64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -855,8 +855,8 @@ fn time_to_lint_conversion() { let res: i64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(12, 1, 20, 391e6 as u32 + 10).unwrap(); - let expected = time.num_seconds_from_midnight() as i64 * 1e9 as i64 + time.nanosecond() as i64; + let time = NaiveTime::from_hms_milli_opt(12, 1, 20, 391).unwrap(); + let expected = time.num_seconds_from_midnight() as i64 * 1000 + i64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -904,8 +904,8 @@ fn tod_to_lint_conversion() { ]); let res: i64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(1, 59, 59, 2567e5 as u32).unwrap(); - let expected = time.num_seconds_from_midnight() as i64 * 1e9 as i64 + time.nanosecond() as i64; + let time = NaiveTime::from_hms_milli_opt(1, 59, 59, 256).unwrap(); + let expected = time.num_seconds_from_midnight() as i64 * 1000 + i64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -954,7 +954,7 @@ fn date_to_lint_conversion() { let date = NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(); let time = NaiveTime::from_hms_opt(0, 0, 0).unwrap(); - let expected = NaiveDateTime::new(date, time).and_utc().timestamp_nanos_opt().unwrap() as u64; + let expected = NaiveDateTime::new(date, time).and_utc().timestamp() as u64; assert_eq!(expected, res) } @@ -1004,7 +1004,7 @@ fn dt_to_lint_conversion() { let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(23, 23, 0).unwrap(); let datetime_utc = TimeZone::from_utc_datetime(&Utc, &naivedatetime_utc); - let expected = datetime_utc.timestamp_nanos_opt().unwrap(); + let expected = datetime_utc.timestamp(); assert_eq!(expected, res) } @@ -1054,8 +1054,8 @@ fn time_to_ulint_conversion() { let res: u64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(12, 1, 20, 391e6 as u32 + 10).unwrap(); - let expected = time.num_seconds_from_midnight() as u64 * 1e9 as u64 + time.nanosecond() as u64; + let time = NaiveTime::from_hms_milli_opt(12, 1, 20, 391).unwrap(); + let expected = time.num_seconds_from_midnight() as u64 * 1000 + u64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -1103,8 +1103,8 @@ fn tod_to_ulint_conversion() { ]); let res: u64 = compile_and_run_no_params(vec![src.into()], includes); - let time = NaiveTime::from_hms_nano_opt(1, 59, 59, 2567e5 as u32).unwrap(); - let expected = time.num_seconds_from_midnight() as u64 * 1e9 as u64 + time.nanosecond() as u64; + let time = NaiveTime::from_hms_milli_opt(1, 59, 59, 256).unwrap(); + let expected = time.num_seconds_from_midnight() as u64 * 1000 + u64::from(time.nanosecond() / 1_000_000); assert_eq!(expected, res) } @@ -1153,7 +1153,7 @@ fn date_to_ulint_conversion() { let date = NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(); let time = NaiveTime::from_hms_opt(0, 0, 0).unwrap(); - let expected = NaiveDateTime::new(date, time).and_utc().timestamp_nanos_opt().unwrap() as u64; + let expected = NaiveDateTime::new(date, time).and_utc().timestamp() as u64; assert_eq!(expected, res) } @@ -1203,7 +1203,7 @@ fn dt_to_ulint_conversion() { let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(23, 23, 0).unwrap(); let datetime_utc = TimeZone::from_utc_datetime(&Utc, &naivedatetime_utc); - let expected = datetime_utc.timestamp_nanos_opt().unwrap() as u64; + let expected = datetime_utc.timestamp() as u64; assert_eq!(expected, res) } @@ -1432,7 +1432,7 @@ fn ltime_to_lreal_conversion() { ]); let res: f64 = compile_and_run_no_params(vec![src.into()], includes); - assert_almost_eq!(9.3784005e13, res, 1e7); + assert_almost_eq!(9.3784005e7, res, 1e1); } // x to ltime @@ -1440,11 +1440,11 @@ fn ltime_to_lreal_conversion() { #[test] fn lword_to_ltime_conversion() { let src = r#" - FUNCTION main : TIME + FUNCTION main : LTIME VAR lw : LWORD := 93784005005005; END_VAR - main := LWORD_TO_TIME(lw); + main := LWORD_TO_LTIME(lw); END_FUNCTION "#; @@ -1486,11 +1486,11 @@ fn lreal_to_ltime_conversion() { #[test] fn lword_to_ldate_conversion() { let src = r#" - FUNCTION main : DATE + FUNCTION main : LDATE VAR lw : LWORD := 123456789000; END_VAR - main := LWORD_TO_DATE(lw); + main := LWORD_TO_LDATE(lw); END_FUNCTION "#; @@ -1509,11 +1509,11 @@ fn lword_to_ldate_conversion() { #[test] fn ulint_to_ldate_conversion() { let src = r#" - FUNCTION main : DATE + FUNCTION main : LDATE VAR ul : ULINT := 1669244400; END_VAR - main := ULINT_TO_DATE(ul); + main := ULINT_TO_LDATE(ul); END_FUNCTION "#; @@ -1532,11 +1532,11 @@ fn ulint_to_ldate_conversion() { fn u64_to_ldate_signed_overflow() { // same behaviour for LWORD and ULINT let src = r#" - FUNCTION main : DATE + FUNCTION main : LDATE VAR ul : ULINT := 9_223_372_036_854_775_807 + 1; //i64::MAX + 1 END_VAR - main := ULINT_TO_DATE(ul); + main := ULINT_TO_LDATE(ul); END_FUNCTION "#; @@ -1554,11 +1554,11 @@ fn u64_to_ldate_signed_overflow() { #[test] fn ulint_to_dt_conversion() { let src = r#" - FUNCTION main : DT + FUNCTION main : LDT VAR ul : ULINT := 1669244400000000; END_VAR - main := ULINT_TO_DT(ul); + main := ULINT_TO_LDT(ul); END_FUNCTION "#; @@ -1577,11 +1577,11 @@ fn ulint_to_dt_conversion() { #[test] fn lword_to_ltod_conversion() { let src = r#" - FUNCTION main : TOD + FUNCTION main : LTOD VAR ul : LWORD := 1669244400000000123; END_VAR - main := LWORD_TO_TOD(ul); + main := LWORD_TO_LTOD(ul); END_FUNCTION "#; @@ -1600,11 +1600,11 @@ fn lword_to_ltod_conversion() { #[test] fn lint_to_ltod_conversion() { let src = r#" - FUNCTION main : TOD + FUNCTION main : LTOD VAR l : LINT := 1669244400000000123; END_VAR - main := LINT_TO_TOD(l); + main := LINT_TO_LTOD(l); END_FUNCTION "#; @@ -1685,17 +1685,17 @@ fn test_time() { assert!(module.mock_time_set_u32(23 * 3600 + 59 * 60 + 30)); let now = module.run::<_, i64>("main", &mut MainType); - let expected = (23 * 3600 + 59 * 60 + 30) * 1e9 as i64 + 100; + let expected = (23 * 3600 + 59 * 60 + 30) * 1000; assert_eq!(expected, now); assert!(module.mock_time_advance_u32(29)); let later = module.run::<_, i64>("main", &mut MainType); - let expected = (23 * 3600 + 59 * 60 + 59) * 1e9 as i64 + 100; + let expected = (23 * 3600 + 59 * 60 + 59) * 1000; assert_eq!(expected, later); assert!(module.mock_time_advance_u32(2)); let new_day = module.run::<_, i64>("main", &mut MainType); - let expected = 1e9 as i64 + 100; + let expected = 1000; assert_eq!(expected, new_day); } @@ -1856,7 +1856,7 @@ fn time_to_string_conversion() { "numerical_functions.st", ]); - let expected = "6d2m123ms456us789ns"; + let expected = "6d2m123ms"; let _: i32 = compile_and_run(vec![src.into()], includes, &mut maintype); let res = unsafe { std::str::from_utf8_unchecked(&maintype.s) }.trim_end_matches('\0'); assert_eq!(expected, res); @@ -1881,7 +1881,7 @@ fn time_to_wstring_conversion() { "numerical_functions.st", ]); - let expected = "6d3h2m9ns"; + let expected = "6d3h2m"; let _: i32 = compile_and_run(vec![src.into()], includes, &mut maintype); let str = String::from_utf16_lossy(&maintype.s); let res = str.trim_end_matches('\0'); diff --git a/libs/stdlib/tests/selectors.rs b/libs/stdlib/tests/selectors.rs index bf18d67671a..e87a1d73966 100644 --- a/libs/stdlib/tests/selectors.rs +++ b/libs/stdlib/tests/selectors.rs @@ -105,7 +105,18 @@ fn test_max_date() { let includes = get_includes(&["selectors.st"]); let res: i64 = compile_and_run_no_params(vec![src.into()], includes); - assert_eq!(res, 40_000_000); + assert_eq!(res, 40); +} + +#[test] +fn test_max_ltime() { + let src = r"FUNCTION main : LTIME + main := MAX(LT#35ns, LT#40ns, LT#1ns, LT#30ns); + END_FUNCTION"; + + let includes = get_includes(&["selectors.st"]); + let res: i64 = compile_and_run_no_params(vec![src.into()], includes); + assert_eq!(res, 40); } #[test] @@ -182,7 +193,18 @@ fn test_min_date() { let includes = get_includes(&["selectors.st"]); let res: i64 = compile_and_run_no_params(vec![src.into()], includes); - assert_eq!(res, 30_000_000); + assert_eq!(res, 30); +} + +#[test] +fn test_min_ltime() { + let src = r"FUNCTION main : LTIME + main := MIN(LT#40ns, LT#1d, LT#30ns, LT#5m); + END_FUNCTION"; + + let includes = get_includes(&["selectors.st"]); + let res: i64 = compile_and_run_no_params(vec![src.into()], includes); + assert_eq!(res, 30); } #[test] @@ -374,3 +396,31 @@ fn test_limit_lreal() { let res: f64 = module.run("main", &mut 60f64); assert!((res - 50f64).abs() <= f64::EPSILON); } + +#[test] +fn test_limit_ltime() { + let src = r#" + FUNCTION main : LTIME + VAR_INPUT {ref} + in : LTIME; + END_VAR + main := LIMIT(LT#10ns, in, LT#50ns); + END_FUNCTION + "#; + + let includes = get_includes(&["selectors.st"]); + let context = CodegenContext::create(); + let module = compile(&context, vec![src.into()], includes); + + // In range, pass value through. + let res: i64 = module.run("main", &mut 30i64); + assert_eq!(30, res); + + // Below range, min is returned. + let res: i64 = module.run("main", &mut 1i64); + assert_eq!(10, res); + + // Above range, max is returned. + let res: i64 = module.run("main", &mut 60i64); + assert_eq!(50, res); +} diff --git a/libs/stdlib/tests/timer_ltime_tests.rs b/libs/stdlib/tests/timer_ltime_tests.rs new file mode 100644 index 00000000000..dd6f6001d02 --- /dev/null +++ b/libs/stdlib/tests/timer_ltime_tests.rs @@ -0,0 +1,202 @@ +use std::time::Duration; + +use common::{compile_and_load, get_includes}; +use iec61131std::timers::{LTime, TimerParamsLTime}; + +// Import common functionality into the integration tests +mod common; + +use plc::codegen::CodegenContext; + +#[repr(C)] +#[derive(Default, Debug)] +struct MainTypeLTime { + value: bool, + tp_out: bool, + tp_et: LTime, + tp_inst: TimerParamsLTime, +} + +#[test] +fn tp_ltime_counts_nanoseconds() { + let prog = r#" + PROGRAM main + VAR_INPUT + value : BOOL; + END_VAR + VAR + tp_out : BOOL; + tp_et : LTIME; + tp_inst : TP_LTIME; + END_VAR + tp_inst(IN := value, PT := LT#100ns, Q => tp_out, ET => tp_et); + END_PROGRAM + "#; + + let sources = vec![prog.into()]; + let includes = get_includes(&["timers.st"]); + let context = CodegenContext::create(); + let module = compile_and_load(&context, sources, includes); + let mut main_inst = MainTypeLTime { value: true, ..MainTypeLTime::default() }; + + // On first call, output is high and elapsed time starts at 0. + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + // Sub-millisecond elapsed time is preserved for LTIME. + assert!(module.mock_time_advance_ns(25)); + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 25); + + // At the preset boundary, ET is clamped to PT and Q is still true. + assert!(module.mock_time_advance_ns(75)); + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 100); + + // Once PT is exceeded, Q goes low and ET stays at PT. + assert!(module.mock_time_advance_ns(1)); + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 100); +} + +#[test] +fn ton_ltime_waits_then_switches_output() { + let prog = r#" + PROGRAM main + VAR_INPUT + value : BOOL; + END_VAR + VAR + tp_out : BOOL; + tp_et : LTIME; + tp_inst : TON_LTIME; + END_VAR + tp_inst(IN := value, PT := LT#30ns, Q => tp_out, ET => tp_et); + END_PROGRAM + "#; + + let sources = vec![prog.into()]; + let includes = get_includes(&["timers.st"]); + let context = CodegenContext::create(); + let module = compile_and_load(&context, sources, includes); + let mut main_inst = MainTypeLTime { value: true, ..MainTypeLTime::default() }; + + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + assert!(module.mock_time_advance_ns(20)); + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 20); + + assert!(module.mock_time_advance_ns(10)); + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 30); + + assert!(module.mock_time_advance_ns(1)); + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 30); + + main_inst.value = false; + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); +} + +#[test] +fn tof_ltime_restarts_when_input_returns_true() { + let prog = r#" + PROGRAM main + VAR_INPUT + value : BOOL; + END_VAR + VAR + tp_out : BOOL; + tp_et : LTIME; + tp_inst : TOF_LTIME; + END_VAR + tp_inst(IN := value, PT := LT#40ns, Q => tp_out, ET => tp_et); + END_PROGRAM + "#; + + let sources = vec![prog.into()]; + let includes = get_includes(&["timers.st"]); + let context = CodegenContext::create(); + let module = compile_and_load(&context, sources, includes); + let mut main_inst = MainTypeLTime { value: true, ..MainTypeLTime::default() }; + + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + main_inst.value = false; + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + assert!(module.mock_time_advance_ns(25)); + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 25); + + // A rising edge while counting should reset ET and keep Q high. + main_inst.value = true; + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + // Falling edge starts counting again from zero. + main_inst.value = false; + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + assert!(module.mock_time_advance_ns(41)); + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 40); +} + +#[test] +fn ton_ltime_large_preset_uses_nanoseconds() { + let prog = r#" + PROGRAM main + VAR_INPUT + value : BOOL; + END_VAR + VAR + tp_out : BOOL; + tp_et : LTIME; + tp_inst : TON_LTIME; + END_VAR + tp_inst(IN := value, PT := LT#10ms, Q => tp_out, ET => tp_et); + END_PROGRAM + "#; + + let sources = vec![prog.into()]; + let includes = get_includes(&["timers.st"]); + let context = CodegenContext::create(); + let module = compile_and_load(&context, sources, includes); + let mut main_inst = MainTypeLTime { value: true, ..MainTypeLTime::default() }; + + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 0); + + assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); + module.run::<_, ()>("main", &mut main_inst); + assert!(!main_inst.tp_out); + assert_eq!(main_inst.tp_et, 5_000_000); + + assert!(module.mock_time_advance_ns(Duration::from_millis(6).as_nanos() as u64)); + module.run::<_, ()>("main", &mut main_inst); + assert!(main_inst.tp_out); + assert_eq!(main_inst.tp_et, 10_000_000); +} diff --git a/libs/stdlib/tests/timer_tests.rs b/libs/stdlib/tests/timer_tests.rs index 9c27490acfa..a5f9b6bfdae 100644 --- a/libs/stdlib/tests/timer_tests.rs +++ b/libs/stdlib/tests/timer_tests.rs @@ -81,17 +81,17 @@ fn tp_true_for_time() { assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); //At 10ms, out is true, et is 10ms assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); //After 15ms, out is false, et is 10/ assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); //After 20ms, input is off, out remains off, et set to 0 assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = false; @@ -131,17 +131,17 @@ fn tp_does_not_retrigger_on_consecutive_input() { assert!(module.mock_time_advance_ns(Duration::from_millis(10).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); //After 15ms, out is false, et is 10/ assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); //After 20ms, out is false, et is 10/ assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); } #[test] @@ -178,7 +178,7 @@ fn tp_not_interrupted_by_signal_change() { module.run::<_, ()>("main", &mut main_inst); //Verify that the timer is still running assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 1_000_000); + assert_eq!(main_inst.tp_et, 1); // advance by 1 ms assert!(module.mock_time_advance_ns(Duration::from_millis(1).as_nanos() as u64)); //call timer with true @@ -186,7 +186,7 @@ fn tp_not_interrupted_by_signal_change() { module.run::<_, ()>("main", &mut main_inst); //assert that the signal was not interrupted assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 2_000_000); + assert_eq!(main_inst.tp_et, 2); } #[test] @@ -219,19 +219,19 @@ fn ton_returns_true_after_time_preset() { main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); // Value true After 10ms -> false assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); // Value true After 15ms -> true assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 10_000_000); + assert_eq!(main_inst.tp_et, 10); // Value false after 20ms -> false assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = false; @@ -298,7 +298,7 @@ fn ton_counts_elapsed_time_while_waiting() { main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); // Value false after 6ms counter at 0ms (stopped) assert!(module.mock_time_advance_ns(Duration::from_millis(1).as_nanos() as u64)); main_inst.value = false; @@ -337,13 +337,13 @@ fn ton_waits_again_after_turining_off() { main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); // Value true After 10ms -> true assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 9_000_000); + assert_eq!(main_inst.tp_et, 9); // Value false After 15ms -> false assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); main_inst.value = false; @@ -361,7 +361,7 @@ fn ton_waits_again_after_turining_off() { main_inst.value = true; module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 9_000_000); + assert_eq!(main_inst.tp_et, 9); } #[test] @@ -399,7 +399,7 @@ fn toff_starts_timer_after_input_is_off() { assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); } #[test] @@ -437,7 +437,7 @@ fn toff_runs_for_preset_time() { assert!(module.mock_time_advance_ns(Duration::from_millis(10).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(!main_inst.tp_out); - assert_eq!(main_inst.tp_et, 9_000_000); + assert_eq!(main_inst.tp_et, 9); //On the next true signal, the timer's elapsed time is set to 0 again // Value true First call -> true @@ -483,7 +483,7 @@ fn toff_keeps_returning_true_if_input_returns_to_true() { assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); //After 16ms, the input becomes true again, the timer stops, et is set to 0 but the signal remains true assert!(module.mock_time_advance_ns(Duration::from_millis(1).as_nanos() as u64)); main_inst.value = true; @@ -500,7 +500,7 @@ fn toff_keeps_returning_true_if_input_returns_to_true() { assert!(module.mock_time_advance_ns(Duration::from_millis(5).as_nanos() as u64)); module.run::<_, ()>("main", &mut main_inst); assert!(main_inst.tp_out); - assert_eq!(main_inst.tp_et, 5_000_000); + assert_eq!(main_inst.tp_et, 5); } #[test] diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 39c70907597..f90fdda6863 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -39,7 +39,9 @@ use crate::{ resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, typesystem::{ self, is_same_type_class, DataType, DataTypeInformation, DataTypeInformationProvider, Dimension, - StringEncoding, VarArgs, DEFAULT_STRING_LEN, DINT_TYPE, LINT_TYPE, + StringEncoding, VarArgs, DATE_AND_TIME_TYPE, DATE_TYPE, DEFAULT_STRING_LEN, DINT_TYPE, + LONG_DATE_AND_TIME_TYPE, LONG_DATE_TYPE, LONG_TIME_OF_DAY_TYPE, LONG_TIME_TYPE, TIME_OF_DAY_TYPE, + TIME_TYPE, }, }; @@ -2456,19 +2458,21 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { AstLiteral::Date(d) => d .value() .map_err(|op| Diagnostic::codegen_error(op.as_str(), location).into()) - .and_then(|ns| self.create_const_int(ns)) + .and_then(|ns| self.create_temporal_const_int(literal_statement, ns)) .map(ExpressionValue::RValue), AstLiteral::DateAndTime(dt) => dt .value() .map_err(|op| Diagnostic::codegen_error(op.as_str(), location).into()) - .and_then(|ns| self.create_const_int(ns)) + .and_then(|ns| self.create_temporal_const_int(literal_statement, ns)) .map(ExpressionValue::RValue), AstLiteral::TimeOfDay(tod) => tod .value() .map_err(|op| Diagnostic::codegen_error(op.as_str(), location).into()) - .and_then(|ns| self.create_const_int(ns)) + .and_then(|ns| self.create_temporal_const_int(literal_statement, ns)) .map(ExpressionValue::RValue), - AstLiteral::Time(t) => self.create_const_int(t.value()).map(ExpressionValue::RValue), + AstLiteral::Time(t) => { + self.create_temporal_const_int(literal_statement, t.value()).map(ExpressionValue::RValue) + } AstLiteral::String(s) => self.generate_string_literal(literal_statement, s.value(), location), AstLiteral::Array(arr) => self .generate_literal_array( @@ -2971,15 +2975,43 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { Ok(phi_value.as_basic_value()) } - fn create_const_int(&self, value: i64) -> Result, CodegenError> { + fn create_const_int_for_type( + &self, + type_name: &str, + value: i64, + ) -> Result, CodegenError> { let value = self.llvm.create_const_numeric( - &self.llvm_index.get_associated_type(LINT_TYPE)?, + &self.llvm_index.get_associated_type(type_name)?, value.to_string().as_str(), SourceLocation::internal(), )?; Ok(value) } + fn create_temporal_const_int( + &self, + literal_statement: &AstNode, + value_in_nanos: i64, + ) -> Result, CodegenError> { + let target_type_name = self.get_type_hint_for(literal_statement)?.get_name(); + + let converted = match target_type_name { + // Short DATE/DT are stored in seconds, so we lower nanosecond literals to whole seconds. + // See `book/src/datatypes.md` for the representation table. + DATE_TYPE | DATE_AND_TIME_TYPE => value_in_nanos / 1_000_000_000, + // Short TIME/TOD are stored in milliseconds, so we lower nanoseconds to whole milliseconds. + // See `book/src/datatypes.md` for the representation table. + TIME_TYPE | TIME_OF_DAY_TYPE => value_in_nanos / 1_000_000, + // Long temporal families retain nanosecond precision. + LONG_DATE_TYPE | LONG_DATE_AND_TIME_TYPE | LONG_TIME_TYPE | LONG_TIME_OF_DAY_TYPE => { + value_in_nanos + } + _ => value_in_nanos, + }; + + self.create_const_int_for_type(target_type_name, converted) + } + /// creates a binary expression (left op right) with generic /// left & right expressions (non-numerics) /// this function attempts to call optional diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_addition_in_var_output.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_addition_in_var_output.snap index df5e1f2be7b..e44bab7135d 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_addition_in_var_output.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_addition_in_var_output.snap @@ -17,11 +17,11 @@ entry: store i32 0, ptr %func, align [filtered] %deref = load ptr, ptr %d_and_t, align [filtered] %deref1 = load ptr, ptr %d_and_t, align [filtered] - %load_d_and_t = load i64, ptr %deref1, align [filtered] + %load_d_and_t = load i32, ptr %deref1, align [filtered] %deref2 = load ptr, ptr %time_var, align [filtered] - %load_time_var = load i64, ptr %deref2, align [filtered] - %tmpVar = add i64 %load_d_and_t, %load_time_var - store i64 %tmpVar, ptr %deref, align [filtered] + %load_time_var = load i32, ptr %deref2, align [filtered] + %tmpVar = add i32 %load_d_and_t, %load_time_var + store i32 %tmpVar, ptr %deref, align [filtered] %func_ret = load i32, ptr %func, align [filtered] ret i32 %func_ret } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_global_constants_initialize.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_global_constants_initialize.snap index f871c4cca32..ce56a6edcae 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_global_constants_initialize.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_and_time_global_constants_initialize.snap @@ -9,72 +9,72 @@ target triple = "[filtered]" %main = type {} -@cT = unnamed_addr constant i64 1000000000 -@cT_SHORT = unnamed_addr constant i64 1000000000 +@cT = unnamed_addr constant i32 1000 +@cT_SHORT = unnamed_addr constant i32 1000 @cLT = unnamed_addr constant i64 1000000000000 @cLT_SHORT = unnamed_addr constant i64 1000000000000 -@cD = unnamed_addr constant i64 0 -@cD_SHORT = unnamed_addr constant i64 161308800000000000 +@cD = unnamed_addr constant i32 0 +@cD_SHORT = unnamed_addr constant i32 161308800 @cLD = unnamed_addr constant i64 161308800000000000 @cLD_SHORT = unnamed_addr constant i64 161308800000000000 -@cTOD = unnamed_addr constant i64 0 -@cTOD_SHORT = unnamed_addr constant i64 0 +@cTOD = unnamed_addr constant i32 0 +@cTOD_SHORT = unnamed_addr constant i32 0 @cLTOD = unnamed_addr constant i64 86399999999999 @cLTOD_SHORT = unnamed_addr constant i64 86399999999999 -@cDT = unnamed_addr constant i64 172799000000000 -@cDT_SHORT = unnamed_addr constant i64 172799000000000 +@cDT = unnamed_addr constant i32 172799 +@cDT_SHORT = unnamed_addr constant i32 172799 @cLDT = unnamed_addr constant i64 172799123000000 @cLDT_SHORT = unnamed_addr constant i64 172799123000000 @main_instance = global %main zeroinitializer define void @main(ptr %0) { entry: - %t1 = alloca i64, align [filtered] - %t2 = alloca i64, align [filtered] + %t1 = alloca i32, align [filtered] + %t2 = alloca i32, align [filtered] %lt1 = alloca i64, align [filtered] %lt2 = alloca i64, align [filtered] - %d1 = alloca i64, align [filtered] - %d2 = alloca i64, align [filtered] + %d1 = alloca i32, align [filtered] + %d2 = alloca i32, align [filtered] %ld1 = alloca i64, align [filtered] %ld2 = alloca i64, align [filtered] - %tod1 = alloca i64, align [filtered] - %tod2 = alloca i64, align [filtered] + %tod1 = alloca i32, align [filtered] + %tod2 = alloca i32, align [filtered] %ltod1 = alloca i64, align [filtered] %ltod2 = alloca i64, align [filtered] - %dt1 = alloca i64, align [filtered] - %dt2 = alloca i64, align [filtered] + %dt1 = alloca i32, align [filtered] + %dt2 = alloca i32, align [filtered] %ldt1 = alloca i64, align [filtered] %ldt2 = alloca i64, align [filtered] - store i64 0, ptr %t1, align [filtered] - store i64 0, ptr %t2, align [filtered] + store i32 0, ptr %t1, align [filtered] + store i32 0, ptr %t2, align [filtered] store i64 0, ptr %lt1, align [filtered] store i64 0, ptr %lt2, align [filtered] - store i64 0, ptr %d1, align [filtered] - store i64 0, ptr %d2, align [filtered] + store i32 0, ptr %d1, align [filtered] + store i32 0, ptr %d2, align [filtered] store i64 0, ptr %ld1, align [filtered] store i64 0, ptr %ld2, align [filtered] - store i64 0, ptr %tod1, align [filtered] - store i64 0, ptr %tod2, align [filtered] + store i32 0, ptr %tod1, align [filtered] + store i32 0, ptr %tod2, align [filtered] store i64 0, ptr %ltod1, align [filtered] store i64 0, ptr %ltod2, align [filtered] - store i64 0, ptr %dt1, align [filtered] - store i64 0, ptr %dt2, align [filtered] + store i32 0, ptr %dt1, align [filtered] + store i32 0, ptr %dt2, align [filtered] store i64 0, ptr %ldt1, align [filtered] store i64 0, ptr %ldt2, align [filtered] - store i64 1000000000, ptr %t1, align [filtered] - store i64 1000000000, ptr %t2, align [filtered] + store i32 1000, ptr %t1, align [filtered] + store i32 1000, ptr %t2, align [filtered] store i64 1000000000000, ptr %lt1, align [filtered] store i64 1000000000000, ptr %lt2, align [filtered] - store i64 0, ptr %d1, align [filtered] - store i64 161308800000000000, ptr %d2, align [filtered] + store i32 0, ptr %d1, align [filtered] + store i32 161308800, ptr %d2, align [filtered] store i64 161308800000000000, ptr %ld1, align [filtered] store i64 161308800000000000, ptr %ld2, align [filtered] - store i64 0, ptr %tod1, align [filtered] - store i64 0, ptr %tod2, align [filtered] + store i32 0, ptr %tod1, align [filtered] + store i32 0, ptr %tod2, align [filtered] store i64 86399999999999, ptr %ltod1, align [filtered] store i64 86399999999999, ptr %ltod2, align [filtered] - store i64 172799000000000, ptr %dt1, align [filtered] - store i64 172799000000000, ptr %dt2, align [filtered] + store i32 172799, ptr %dt1, align [filtered] + store i32 172799, ptr %dt2, align [filtered] store i64 172799123000000, ptr %ldt1, align [filtered] store i64 172799123000000, ptr %ldt2, align [filtered] ret void diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_comparisons.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_comparisons.snap index dd9a38e73b6..880ac870448 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_comparisons.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__date_comparisons.snap @@ -7,7 +7,7 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64, i64, i64, i64 } +%prg = type { i32, i32, i32, i32 } @prg_instance = global %prg zeroinitializer @@ -17,13 +17,13 @@ entry: %b = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 1 %c = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 2 %d = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 3 - %load_a = load i64, ptr %a, align [filtered] - %tmpVar = icmp sgt i64 %load_a, 1619827200000000000 - %load_b = load i64, ptr %b, align [filtered] - %tmpVar1 = icmp sgt i64 %load_b, 1619897357000000000 - %load_c = load i64, ptr %c, align [filtered] - %tmpVar2 = icmp sgt i64 %load_c, 156557000000000 - %load_d = load i64, ptr %d, align [filtered] - %tmpVar3 = icmp sgt i64 %load_d, 70157000000000 + %load_a = load i32, ptr %a, align [filtered] + %tmpVar = icmp sgt i32 %load_a, 1619827200 + %load_b = load i32, ptr %b, align [filtered] + %tmpVar1 = icmp sgt i32 %load_b, 1619897357 + %load_c = load i32, ptr %c, align [filtered] + %tmpVar2 = icmp sgt i32 %load_c, 156557000 + %load_d = load i32, ptr %d, align [filtered] + %tmpVar3 = icmp sgt i32 %load_d, 70157000 ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__function_call_with_same_name_as_return_type.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__function_call_with_same_name_as_return_type.snap index c9f41933740..d0d85f147f7 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__function_call_with_same_name_as_return_type.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__function_call_with_same_name_as_return_type.snap @@ -11,16 +11,16 @@ target triple = "[filtered]" @prg_instance = global %prg zeroinitializer -define i64 @TIME() { +define i32 @TIME() { entry: - %TIME = alloca i64, align [filtered] - store i64 0, ptr %TIME, align [filtered] - %TIME_ret = load i64, ptr %TIME, align [filtered] - ret i64 %TIME_ret + %TIME = alloca i32, align [filtered] + store i32 0, ptr %TIME, align [filtered] + %TIME_ret = load i32, ptr %TIME, align [filtered] + ret i32 %TIME_ret } define void @prg(ptr %0) { entry: - %call = call i64 @TIME() + %call = call i32 @TIME() ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment.snap index 2ecb99e713e..852d17aa29e 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment.snap @@ -7,7 +7,7 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64, i64, i64, i64 } +%prg = type { i32, i32, i32, i32 } @prg_instance = global %prg zeroinitializer @@ -17,17 +17,17 @@ entry: %x = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 1 %y = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 2 %z = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 3 - store i64 56190123000000, ptr %w, align [filtered] - store i64 56190123000000, ptr %w, align [filtered] - store i64 100012000000, ptr %x, align [filtered] - store i64 100012000000, ptr %x, align [filtered] - store i64 465436800000000000, ptr %y, align [filtered] - store i64 0, ptr %y, align [filtered] - store i64 465509714000000000, ptr %z, align [filtered] - store i64 58804123000000, ptr %z, align [filtered] - store i64 58804123456789, ptr %z, align [filtered] - store i64 946757700000000000, ptr %z, align [filtered] - store i64 946757700000000000, ptr %z, align [filtered] - store i64 946757708123000000, ptr %z, align [filtered] + store i32 56190123, ptr %w, align [filtered] + store i32 56190123, ptr %w, align [filtered] + store i32 100012, ptr %x, align [filtered] + store i32 100012, ptr %x, align [filtered] + store i32 465436800, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 465509714, ptr %z, align [filtered] + store i32 58804, ptr %z, align [filtered] + store i32 58804, ptr %z, align [filtered] + store i32 946757700, ptr %z, align [filtered] + store i32 946757700, ptr %z, align [filtered] + store i32 946757708, ptr %z, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment_whit_short_datatype_names.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment_whit_short_datatype_names.snap index 335fbe4d32d..3e6a0dc343f 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment_whit_short_datatype_names.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_date_assignment_whit_short_datatype_names.snap @@ -7,7 +7,7 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64, i64, i64, i64 } +%prg = type { i32, i32, i32, i32 } @prg_instance = global %prg zeroinitializer @@ -17,14 +17,14 @@ entry: %x = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 1 %y = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 2 %z = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 3 - store i64 56190123000000, ptr %w, align [filtered] - store i64 56190123000000, ptr %w, align [filtered] - store i64 100012000000, ptr %x, align [filtered] - store i64 100012000000, ptr %x, align [filtered] - store i64 465436800000000000, ptr %y, align [filtered] - store i64 0, ptr %y, align [filtered] - store i64 465509700000000000, ptr %z, align [filtered] - store i64 58808123000000, ptr %z, align [filtered] - store i64 58804123456789, ptr %z, align [filtered] + store i32 56190123, ptr %w, align [filtered] + store i32 56190123, ptr %w, align [filtered] + store i32 100012, ptr %x, align [filtered] + store i32 100012, ptr %x, align [filtered] + store i32 465436800, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 465509700, ptr %z, align [filtered] + store i32 58808, ptr %z, align [filtered] + store i32 58804, ptr %z, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_assignment.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_assignment.snap index f289f3fb21a..a721076cc91 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_assignment.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_assignment.snap @@ -7,21 +7,21 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64 } +%prg = type { i32 } @prg_instance = global %prg zeroinitializer define void @prg(ptr %0) { entry: %y = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 0 - store i64 0, ptr %y, align [filtered] - store i64 43200000000000, ptr %y, align [filtered] - store i64 100000000, ptr %y, align [filtered] - store i64 100000000, ptr %y, align [filtered] - store i64 1000000, ptr %y, align [filtered] - store i64 -1000, ptr %y, align [filtered] - store i64 1, ptr %y, align [filtered] - store i64 -86400001000000, ptr %y, align [filtered] - store i64 8640000001000000, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 43200000, ptr %y, align [filtered] + store i32 100, ptr %y, align [filtered] + store i32 100, ptr %y, align [filtered] + store i32 1, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 -86400001, ptr %y, align [filtered] + store i32 50065409, ptr %y, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_of_day_assignment.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_of_day_assignment.snap index 4bd6f9cbf8a..3e714331ade 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_of_day_assignment.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__program_with_time_of_day_assignment.snap @@ -7,20 +7,20 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64 } +%prg = type { i32 } @prg_instance = global %prg zeroinitializer define void @prg(ptr %0) { entry: %y = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 0 - store i64 0, ptr %y, align [filtered] - store i64 3600000000000, ptr %y, align [filtered] - store i64 3600001000000, ptr %y, align [filtered] - store i64 3661000000000, ptr %y, align [filtered] - store i64 72900000000000, ptr %y, align [filtered] - store i64 72900000000000, ptr %y, align [filtered] - store i64 40260000000000, ptr %y, align [filtered] - store i64 40260000000000, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 3600000, ptr %y, align [filtered] + store i32 3600001, ptr %y, align [filtered] + store i32 3661000, ptr %y, align [filtered] + store i32 72900000, ptr %y, align [filtered] + store i32 72900000, ptr %y, align [filtered] + store i32 40260000, ptr %y, align [filtered] + store i32 40260000, ptr %y, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__time_variables_have_nano_seconds_resolution.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__time_variables_have_nano_seconds_resolution.snap index 9fae4bbf5f5..f16f7a24320 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__time_variables_have_nano_seconds_resolution.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__time_variables_have_nano_seconds_resolution.snap @@ -7,16 +7,16 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i64 } +%prg = type { i32 } @prg_instance = global %prg zeroinitializer define void @prg(ptr %0) { entry: %y = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 0 - store i64 1000000, ptr %y, align [filtered] - store i64 1000, ptr %y, align [filtered] - store i64 100, ptr %y, align [filtered] - store i64 8640000001125000, ptr %y, align [filtered] + store i32 1, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 0, ptr %y, align [filtered] + store i32 50065409, ptr %y, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__variable_with_same_name_as_data_type.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__variable_with_same_name_as_data_type.snap index 4d7af610484..30619561efc 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__variable_with_same_name_as_data_type.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__variable_with_same_name_as_data_type.snap @@ -7,18 +7,18 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prog = type { i64 } +%prog = type { i32 } @prog_instance = global %prog zeroinitializer -define i64 @func() { +define i32 @func() { entry: - %func = alloca i64, align [filtered] - %TIME = alloca i64, align [filtered] - store i64 0, ptr %TIME, align [filtered] - store i64 0, ptr %func, align [filtered] - %func_ret = load i64, ptr %func, align [filtered] - ret i64 %func_ret + %func = alloca i32, align [filtered] + %TIME = alloca i32, align [filtered] + store i32 0, ptr %TIME, align [filtered] + store i32 0, ptr %func, align [filtered] + %func_ret = load i32, ptr %func, align [filtered] + ret i32 %func_ret } define void @prog(ptr %0) { diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__compare_instructions_tests__compare_datetime_types.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__compare_instructions_tests__compare_datetime_types.snap index 8986e0f4161..ac3c1e47c6a 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__compare_instructions_tests__compare_datetime_types.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__compare_instructions_tests__compare_datetime_types.snap @@ -7,7 +7,7 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%main = type { i64, i64, i64, i64 } +%main = type { i32, i32, i32, i32 } @main_instance = global %main zeroinitializer @@ -17,16 +17,16 @@ entry: %var_time_of_day = getelementptr inbounds nuw %main, ptr %0, i32 0, i32 1 %var_date = getelementptr inbounds nuw %main, ptr %0, i32 0, i32 2 %var_date_and_time = getelementptr inbounds nuw %main, ptr %0, i32 0, i32 3 - %load_var_time = load i64, ptr %var_time, align [filtered] - %load_var_time_of_day = load i64, ptr %var_time_of_day, align [filtered] - %tmpVar = icmp sgt i64 %load_var_time, %load_var_time_of_day - %load_var_time_of_day1 = load i64, ptr %var_time_of_day, align [filtered] - %load_var_date = load i64, ptr %var_date, align [filtered] - %tmpVar2 = icmp sgt i64 %load_var_time_of_day1, %load_var_date + %load_var_time = load i32, ptr %var_time, align [filtered] + %load_var_time_of_day = load i32, ptr %var_time_of_day, align [filtered] + %tmpVar = icmp sgt i32 %load_var_time, %load_var_time_of_day + %load_var_time_of_day1 = load i32, ptr %var_time_of_day, align [filtered] + %load_var_date = load i32, ptr %var_date, align [filtered] + %tmpVar2 = icmp sgt i32 %load_var_time_of_day1, %load_var_date %1 = and i1 %tmpVar, %tmpVar2 - %load_var_date3 = load i64, ptr %var_date, align [filtered] - %load_var_date_and_time = load i64, ptr %var_date_and_time, align [filtered] - %tmpVar4 = icmp sgt i64 %load_var_date3, %load_var_date_and_time + %load_var_date3 = load i32, ptr %var_date, align [filtered] + %load_var_date_and_time = load i32, ptr %var_date_and_time, align [filtered] + %tmpVar4 = icmp sgt i32 %load_var_date3, %load_var_date_and_time %2 = and i1 %1, %tmpVar4 %3 = zext i1 %2 to i8 ret void diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__generics_test__generic_output_parameter.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__generics_test__generic_output_parameter.snap index e04c7e57b3b..f510e6b2463 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__generics_test__generic_output_parameter.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__generics_test__generic_output_parameter.snap @@ -7,15 +7,15 @@ source_filename = "" target datalayout = "[filtered]" target triple = "[filtered]" -%prg = type { i16, i16, i64 } +%prg = type { i16, i16, i32 } @prg_instance = global %prg zeroinitializer -define i16 @foo__INT(i64 %0, ptr %1) { +define i16 @foo__INT(i32 %0, ptr %1) { entry: %foo__INT = alloca i16, align [filtered] - %in1 = alloca i64, align [filtered] - store i64 %0, ptr %in1, align [filtered] + %in1 = alloca i32, align [filtered] + store i32 %0, ptr %in1, align [filtered] %out1 = alloca ptr, align [filtered] store ptr %1, ptr %out1, align [filtered] store i16 0, ptr %foo__INT, align [filtered] @@ -28,8 +28,8 @@ entry: %theInt = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 0 %iResult = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 1 %data = getelementptr inbounds nuw %prg, ptr %0, i32 0, i32 2 - %load_data = load i64, ptr %data, align [filtered] - %call = call i16 @foo__INT(i64 %load_data, ptr %theInt) + %load_data = load i32, ptr %data, align [filtered] + %call = call i16 @foo__INT(i32 %load_data, ptr %theInt) store i16 %call, ptr %iResult, align [filtered] ret void } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__function_var_constant_strings_should_be_collected_as_literals.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__function_var_constant_strings_should_be_collected_as_literals.snap index dcc76f96a5b..65419aa00ac 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__function_var_constant_strings_should_be_collected_as_literals.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__function_var_constant_strings_should_be_collected_as_literals.snap @@ -12,18 +12,18 @@ target triple = "[filtered]" @utf08_literal_0 = private unnamed_addr constant [2 x i8] c"#\00" @utf08_literal_1 = private unnamed_addr constant [2 x i8] c"*\00" -define i64 @FSTRING_TO_DT() { +define i32 @FSTRING_TO_DT() { entry: - %FSTRING_TO_DT = alloca i64, align [filtered] + %FSTRING_TO_DT = alloca i32, align [filtered] %ignore = alloca [2 x i8], align [filtered] %fchar = alloca [2 x i8], align [filtered] call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %ignore, ptr align [filtered] @__FSTRING_TO_DT.ignore__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %fchar, ptr align [filtered] @__FSTRING_TO_DT.fchar__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) - store i64 0, ptr %FSTRING_TO_DT, align [filtered] + store i32 0, ptr %FSTRING_TO_DT, align [filtered] call void @llvm.memcpy.p0.p0.i32(ptr align [filtered] %fchar, ptr align [filtered] @utf08_literal_0, i32 1, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align [filtered] %ignore, ptr align [filtered] @utf08_literal_1, i32 1, i1 false) - %FSTRING_TO_DT_ret = load i64, ptr %FSTRING_TO_DT, align [filtered] - ret i64 %FSTRING_TO_DT_ret + %FSTRING_TO_DT_ret = load i32, ptr %FSTRING_TO_DT, align [filtered] + ret i32 %FSTRING_TO_DT_ret } ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable.snap index 1d29719ab3f..668346ae125 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable.snap @@ -22,16 +22,16 @@ entry: ret i8 %STRING_EQUAL_ret } -define i64 @FSTRING_TO_DT() { +define i32 @FSTRING_TO_DT() { entry: - %FSTRING_TO_DT = alloca i64, align [filtered] + %FSTRING_TO_DT = alloca i32, align [filtered] %ignore = alloca [2 x i8], align [filtered] %fchar = alloca [2 x i8], align [filtered] %c = alloca [2 x i8], align [filtered] call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %ignore, ptr align [filtered] @__FSTRING_TO_DT.ignore__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %fchar, ptr align [filtered] @__FSTRING_TO_DT.fchar__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) call void @llvm.memset.p0.i64(ptr align [filtered] %c, i8 0, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) - store i64 0, ptr %FSTRING_TO_DT, align [filtered] + store i32 0, ptr %FSTRING_TO_DT, align [filtered] %call = call i8 @STRING_EQUAL(ptr %c, ptr %ignore) %0 = icmp ne i8 %call, 0 br i1 %0, label %condition_body, label %continue @@ -40,8 +40,8 @@ condition_body: ; preds = %entry br label %continue continue: ; preds = %condition_body, %entry - %FSTRING_TO_DT_ret = load i64, ptr %FSTRING_TO_DT, align [filtered] - ret i64 %FSTRING_TO_DT_ret + %FSTRING_TO_DT_ret = load i32, ptr %FSTRING_TO_DT, align [filtered] + ret i32 %FSTRING_TO_DT_ret } ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable_nonref.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable_nonref.snap index ccffbdf5d3b..ee5474065aa 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable_nonref.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__string_tests__using_a_constant_var_string_should_be_memcpyable_nonref.snap @@ -24,16 +24,16 @@ entry: ret i8 %STRING_EQUAL_ret } -define i64 @FSTRING_TO_DT() { +define i32 @FSTRING_TO_DT() { entry: - %FSTRING_TO_DT = alloca i64, align [filtered] + %FSTRING_TO_DT = alloca i32, align [filtered] %ignore = alloca [2 x i8], align [filtered] %fchar = alloca [2 x i8], align [filtered] %c = alloca [2 x i8], align [filtered] call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %ignore, ptr align [filtered] @__FSTRING_TO_DT.ignore__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) call void @llvm.memcpy.p0.p0.i64(ptr align [filtered] %fchar, ptr align [filtered] @__FSTRING_TO_DT.fchar__init, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) call void @llvm.memset.p0.i64(ptr align [filtered] %c, i8 0, i64 ptrtoint (ptr getelementptr ([2 x i8], ptr null, i32 1) to i64), i1 false) - store i64 0, ptr %FSTRING_TO_DT, align [filtered] + store i32 0, ptr %FSTRING_TO_DT, align [filtered] %call = call i8 @STRING_EQUAL(ptr %c, ptr %ignore) %0 = icmp ne i8 %call, 0 br i1 %0, label %condition_body, label %continue @@ -42,8 +42,8 @@ condition_body: ; preds = %entry br label %continue continue: ; preds = %condition_body, %entry - %FSTRING_TO_DT_ret = load i64, ptr %FSTRING_TO_DT, align [filtered] - ret i64 %FSTRING_TO_DT_ret + %FSTRING_TO_DT_ret = load i32, ptr %FSTRING_TO_DT, align [filtered] + ret i32 %FSTRING_TO_DT_ret } ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) diff --git a/src/parser/expressions_parser.rs b/src/parser/expressions_parser.rs index ab64812d3d2..002abd21072 100644 --- a/src/parser/expressions_parser.rs +++ b/src/parser/expressions_parser.rs @@ -701,6 +701,7 @@ fn parse_date_from_string( text: &str, location: SourceLocation, id: AstId, + is_long: bool, ) -> Option { let mut segments = text.split('-'); @@ -718,14 +719,15 @@ fn parse_date_from_string( .map(|s| parse_number::(lexer, s, &location)) .expect("day-segment - tokenizer broken?")?; - Some(AstNode::new_literal(AstLiteral::new_date(year, month, day), id, location)) + Some(AstNode::new_literal(AstLiteral::new_date_with_long_flag(year, month, day, is_long), id, location)) } fn parse_literal_date_and_time(lexer: &mut ParseSession) -> Option { let location = lexer.location(); //get rid of D# or DATE# - let slice = lexer.slice_and_advance(); + let slice = lexer.slice_and_advance().to_string(); let hash_location = slice.find('#').unwrap_or_default(); + let is_long = slice[..hash_location].starts_with('L') || slice[..hash_location].starts_with('l'); let last_minus_location = slice.rfind('-').expect("unexpected date-and-time syntax"); let (_, date_and_time) = slice.split_at(hash_location + 1); //get rid of the prefix @@ -742,35 +744,43 @@ fn parse_literal_date_and_time(lexer: &mut ParseSession) -> Option { let mut segments = time.split(':'); let (hour, min, sec, nano) = parse_time_of_day(lexer, &mut segments, &location)?; - Some(AstNode::new_literal( - AstLiteral::new_date_and_time(year, month, day, hour, min, sec, nano), - lexer.next_id(), - location, - )) + let literal = if is_long { + AstLiteral::new_long_date_and_time(year, month, day, hour, min, sec, nano) + } else { + AstLiteral::new_date_and_time(year, month, day, hour, min, sec, nano) + }; + + Some(AstNode::new_literal(literal, lexer.next_id(), location)) } fn parse_literal_date(lexer: &mut ParseSession) -> Option { let location = lexer.location(); //get rid of D# or DATE# - let slice = lexer.slice_and_advance(); + let slice = lexer.slice_and_advance().to_string(); let hash_location = slice.find('#').unwrap_or_default(); + let is_long = slice[..hash_location].starts_with('L') || slice[..hash_location].starts_with('l'); let (_, slice) = slice.split_at(hash_location + 1); //get rid of the prefix - let next_id = lexer.next_id(); - parse_date_from_string(lexer, slice, location, next_id) + let id = lexer.next_id(); + parse_date_from_string(lexer, slice, location, id, is_long) } fn parse_literal_time_of_day(lexer: &mut ParseSession) -> Option { let location = lexer.location(); //get rid of TOD# or TIME_OF_DAY# - let slice = lexer.slice_and_advance(); + let slice = lexer.slice_and_advance().to_string(); let hash_location = slice.find('#').unwrap_or_default(); + let is_long = slice[..hash_location].starts_with('L') || slice[..hash_location].starts_with('l'); let (_, slice) = slice.split_at(hash_location + 1); //get rid of the prefix let mut segments = slice.split(':'); let (hour, min, sec, nano) = parse_time_of_day(lexer, &mut segments, &location)?; - Some(AstNode::new_literal(AstLiteral::new_time_of_day(hour, min, sec, nano), lexer.next_id(), location)) + Some(AstNode::new_literal( + AstLiteral::new_time_of_day_with_long_flag(hour, min, sec, nano, is_long), + lexer.next_id(), + location, + )) } fn parse_time_of_day( @@ -802,8 +812,10 @@ fn parse_literal_time(lexer: &mut ParseSession) -> Option { const POS_NS: usize = 6; let location = lexer.location(); //get rid of T# or TIME# - let slice = lexer.slice_and_advance(); - let (_, slice) = slice.split_at(slice.find('#').unwrap_or_default() + 1); //get rid of the prefix + let slice = lexer.slice_and_advance().to_string(); + let hash_location = slice.find('#').unwrap_or_default(); + let is_long = slice[..hash_location].starts_with('L') || slice[..hash_location].starts_with('l'); + let (_, slice) = slice.split_at(hash_location + 1); //get rid of the prefix let mut chars = slice.char_indices(); let mut char = chars.next(); @@ -907,6 +919,7 @@ fn parse_literal_time(lexer: &mut ParseSession) -> Option { micro: values[POS_US].unwrap_or_default(), nano: values[POS_NS].map(|it| it as u32).unwrap_or(0u32), negative: is_negative, + is_long, }), lexer.next_id(), location, diff --git a/src/resolver.rs b/src/resolver.rs index a4e7006cfbe..828d64bdf9b 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -30,8 +30,9 @@ use crate::{ index::{ArgumentType, Index, PouIndexEntry, VariableIndexEntry, VariableType}, typesystem::{ self, get_bigger_type, DataTypeInformation, InternalType, StringEncoding, StructSource, BOOL_TYPE, - BYTE_TYPE, DATE_AND_TIME_TYPE, DATE_TYPE, DINT_TYPE, DWORD_TYPE, LINT_TYPE, LREAL_TYPE, LWORD_TYPE, - REAL_TYPE, TIME_OF_DAY_TYPE, TIME_TYPE, VOID_TYPE, WORD_TYPE, + BYTE_TYPE, DATE_AND_TIME_TYPE, DATE_TYPE, DINT_TYPE, DWORD_TYPE, LINT_TYPE, LONG_DATE_AND_TIME_TYPE, + LONG_DATE_TYPE, LONG_TIME_OF_DAY_TYPE, LONG_TIME_TYPE, LREAL_TYPE, LWORD_TYPE, REAL_TYPE, + TIME_OF_DAY_TYPE, TIME_TYPE, VOID_TYPE, WORD_TYPE, }, }; use crate::{ @@ -2829,17 +2830,23 @@ impl<'i> TypeAnnotator<'i> { AstLiteral::Integer(value) => { self.annotate(statement, StatementAnnotation::value(get_int_type_name_for(*value))); } - AstLiteral::Time { .. } => { - self.annotate(statement, StatementAnnotation::value(TIME_TYPE)) + AstLiteral::Time(value) => { + let type_name = if value.is_long() { LONG_TIME_TYPE } else { TIME_TYPE }; + self.annotate(statement, StatementAnnotation::value(type_name)) } - AstLiteral::TimeOfDay { .. } => { - self.annotate(statement, StatementAnnotation::value(TIME_OF_DAY_TYPE)); + AstLiteral::TimeOfDay(value) => { + let type_name = + if value.is_long() { LONG_TIME_OF_DAY_TYPE } else { TIME_OF_DAY_TYPE }; + self.annotate(statement, StatementAnnotation::value(type_name)); } - AstLiteral::Date { .. } => { - self.annotate(statement, StatementAnnotation::value(DATE_TYPE)); + AstLiteral::Date(value) => { + let type_name = if value.is_long() { LONG_DATE_TYPE } else { DATE_TYPE }; + self.annotate(statement, StatementAnnotation::value(type_name)); } - AstLiteral::DateAndTime { .. } => { - self.annotate(statement, StatementAnnotation::value(DATE_AND_TIME_TYPE)); + AstLiteral::DateAndTime(value) => { + let type_name = + if value.is_long() { LONG_DATE_AND_TIME_TYPE } else { DATE_AND_TIME_TYPE }; + self.annotate(statement, StatementAnnotation::value(type_name)); } AstLiteral::Real(value) => { // XXX: if we have a float literal in an initializer (lhs) context, we need to see if the context expects a double or float type. diff --git a/src/resolver/tests/resolve_literals_tests.rs b/src/resolver/tests/resolve_literals_tests.rs index 917ef26ba52..ea0cbdcda54 100644 --- a/src/resolver/tests/resolve_literals_tests.rs +++ b/src/resolver/tests/resolve_literals_tests.rs @@ -161,7 +161,7 @@ fn long_date_literals_are_annotated() { let (annotations, ..) = TypeAnnotator::visit_unit(&index, &unit, id_provider); let statements = &unit.implementations[0].statements; - let expected_types = ["TIME", "DATE", "DATE_AND_TIME", "TIME_OF_DAY"]; + let expected_types = ["LTIME", "LDATE", "LDATE_AND_TIME", "LTIME_OF_DAY"]; for (i, s) in statements.iter().enumerate() { assert_eq!(expected_types[i], annotations.get_type_or_void(s, &index).get_name(), "{:#?}", s); } diff --git a/src/typesystem.rs b/src/typesystem.rs index e15a167e6af..466126581ba 100644 --- a/src/typesystem.rs +++ b/src/typesystem.rs @@ -50,7 +50,8 @@ pub const DINT_SIZE: u32 = NativeDintType::BITS; pub const LINT_SIZE: u32 = NativeLintType::BITS; pub const REAL_SIZE: u32 = (size_of::() * 8) as u32; pub const LREAL_SIZE: u32 = (size_of::() * 8) as u32; -pub const DATE_TIME_SIZE: u32 = 64; +pub const SHORT_DATE_TIME_SIZE: u32 = DINT_SIZE; +pub const LONG_DATE_TIME_SIZE: u32 = LINT_SIZE; pub const POINTER_SIZE: u32 = NativePointerType::BITS; pub const U1_TYPE: &str = "__U1"; @@ -700,7 +701,17 @@ impl DataTypeInformation { } pub fn is_date_or_time_type(&self) -> bool { - matches!(self.get_name(), DATE_TYPE | DATE_AND_TIME_TYPE | TIME_OF_DAY_TYPE | TIME_TYPE) + matches!( + self.get_name(), + DATE_TYPE + | DATE_AND_TIME_TYPE + | TIME_OF_DAY_TYPE + | TIME_TYPE + | LONG_DATE_TYPE + | LONG_DATE_AND_TIME_TYPE + | LONG_TIME_OF_DAY_TYPE + | LONG_TIME_TYPE + ) } pub fn is_function_pointer(&self) -> bool { @@ -1181,8 +1192,8 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Integer { name: DATE_TYPE.into(), - signed: true, - size: DATE_TIME_SIZE, + signed: false, + size: SHORT_DATE_TIME_SIZE, semantic_size: None, }, nature: TypeNature::Date, @@ -1194,8 +1205,8 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Integer { name: TIME_TYPE.into(), - signed: true, - size: DATE_TIME_SIZE, + signed: false, + size: SHORT_DATE_TIME_SIZE, semantic_size: None, }, nature: TypeNature::Duration, @@ -1207,8 +1218,8 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Integer { name: DATE_AND_TIME_TYPE.into(), - signed: true, - size: DATE_TIME_SIZE, + signed: false, + size: SHORT_DATE_TIME_SIZE, semantic_size: None, }, nature: TypeNature::Date, @@ -1220,8 +1231,8 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Integer { name: TIME_OF_DAY_TYPE.into(), - signed: true, - size: DATE_TIME_SIZE, + signed: false, + size: SHORT_DATE_TIME_SIZE, semantic_size: None, }, nature: TypeNature::Date, @@ -1295,7 +1306,7 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Alias { name: LONG_DATE_AND_TIME_TYPE_SHORTENED.into(), - referenced_type: DATE_AND_TIME_TYPE.into(), + referenced_type: LONG_DATE_AND_TIME_TYPE.into(), }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1304,9 +1315,11 @@ pub fn get_builtin_types() -> Vec { DataType { name: LONG_DATE_AND_TIME_TYPE.into(), initial_value: None, - information: DataTypeInformation::Alias { + information: DataTypeInformation::Integer { name: LONG_DATE_AND_TIME_TYPE.into(), - referenced_type: DATE_AND_TIME_TYPE.into(), + signed: true, + size: LONG_DATE_TIME_SIZE, + semantic_size: None, }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1326,9 +1339,11 @@ pub fn get_builtin_types() -> Vec { DataType { name: LONG_DATE_TYPE.into(), initial_value: None, - information: DataTypeInformation::Alias { + information: DataTypeInformation::Integer { name: LONG_DATE_TYPE.into(), - referenced_type: DATE_TYPE.into(), + signed: true, + size: LONG_DATE_TIME_SIZE, + semantic_size: None, }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1339,7 +1354,7 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Alias { name: LONG_DATE_TYPE_SHORTENED.into(), - referenced_type: DATE_TYPE.into(), + referenced_type: LONG_DATE_TYPE.into(), }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1359,9 +1374,11 @@ pub fn get_builtin_types() -> Vec { DataType { name: LONG_TIME_OF_DAY_TYPE.into(), initial_value: None, - information: DataTypeInformation::Alias { + information: DataTypeInformation::Integer { name: LONG_TIME_OF_DAY_TYPE.into(), - referenced_type: TIME_OF_DAY_TYPE.into(), + signed: true, + size: LONG_DATE_TIME_SIZE, + semantic_size: None, }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1372,7 +1389,7 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Alias { name: LONG_TIME_OF_DAY_TYPE_SHORTENED.into(), - referenced_type: TIME_OF_DAY_TYPE.into(), + referenced_type: LONG_TIME_OF_DAY_TYPE.into(), }, nature: TypeNature::Date, location: SourceLocation::internal(), @@ -1392,9 +1409,11 @@ pub fn get_builtin_types() -> Vec { DataType { name: LONG_TIME_TYPE.into(), initial_value: None, - information: DataTypeInformation::Alias { + information: DataTypeInformation::Integer { name: LONG_TIME_TYPE.into(), - referenced_type: TIME_TYPE.into(), + signed: true, + size: LONG_DATE_TIME_SIZE, + semantic_size: None, }, nature: TypeNature::Duration, location: SourceLocation::internal(), @@ -1405,7 +1424,7 @@ pub fn get_builtin_types() -> Vec { initial_value: None, information: DataTypeInformation::Alias { name: LONG_TIME_TYPE_SHORTENED.into(), - referenced_type: TIME_TYPE.into(), + referenced_type: LONG_TIME_TYPE.into(), }, nature: TypeNature::Duration, location: SourceLocation::internal(), @@ -1615,10 +1634,14 @@ pub fn get_literal_actual_signed_type_name(lit: &AstLiteral, signed: bool) -> Op AstLiteral::String(StringValue { is_wide: true, .. }) => Some(WSTRING_TYPE), AstLiteral::String(StringValue { is_wide: false, .. }) => Some(STRING_TYPE), AstLiteral::Real { .. } => Some(LREAL_TYPE), - AstLiteral::Date { .. } => Some(DATE_TYPE), - AstLiteral::DateAndTime { .. } => Some(DATE_AND_TIME_TYPE), - AstLiteral::Time { .. } => Some(TIME_TYPE), - AstLiteral::TimeOfDay { .. } => Some(TIME_OF_DAY_TYPE), + AstLiteral::Date(date) => Some(if date.is_long() { LONG_DATE_TYPE } else { DATE_TYPE }), + AstLiteral::DateAndTime(date_time) => { + Some(if date_time.is_long() { LONG_DATE_AND_TIME_TYPE } else { DATE_AND_TIME_TYPE }) + } + AstLiteral::Time(time) => Some(if time.is_long() { LONG_TIME_TYPE } else { TIME_TYPE }), + AstLiteral::TimeOfDay(time_of_day) => { + Some(if time_of_day.is_long() { LONG_TIME_OF_DAY_TYPE } else { TIME_OF_DAY_TYPE }) + } _ => None, } } diff --git a/src/validation/statement.rs b/src/validation/statement.rs index 8794f5b7c98..8068c52e913 100644 --- a/src/validation/statement.rs +++ b/src/validation/statement.rs @@ -58,6 +58,46 @@ pub fn visit_statement( // AstStatement::LiteralReal { value, location, id } => (), // AstStatement::LiteralBool { value, location, id } => (), // AstStatement::LiteralString { value, is_wide, location, id } => (), + AstStatement::Literal(AstLiteral::Date(date)) => { + validate_temporal_literal_bounds( + validator, + date.value(), + date.is_long(), + "DATE", + 1_000_000_000, + &statement.location, + ); + } + AstStatement::Literal(AstLiteral::DateAndTime(date_time)) => { + validate_temporal_literal_bounds( + validator, + date_time.value(), + date_time.is_long(), + "DATE_AND_TIME", + 1_000_000_000, + &statement.location, + ); + } + AstStatement::Literal(AstLiteral::TimeOfDay(time_of_day)) => { + validate_temporal_literal_bounds( + validator, + time_of_day.value(), + time_of_day.is_long(), + "TIME_OF_DAY", + 1_000_000, + &statement.location, + ); + } + AstStatement::Literal(AstLiteral::Time(time)) => { + validate_temporal_literal_bounds( + validator, + Ok(time.value()), + time.is_long(), + "TIME", + 1_000_000, + &statement.location, + ); + } AstStatement::Literal(AstLiteral::Array(Array { elements: Some(elements) })) => { visit_statement(validator, elements.as_ref(), context); } @@ -180,6 +220,42 @@ pub fn visit_statement( validate_type_nature(validator, statement, context); } +fn validate_temporal_literal_bounds( + validator: &mut Validator, + literal_value: Result, + is_long: bool, + literal_name: &str, + short_unit_divisor: i64, + location: &SourceLocation, +) { + fn emit_warning(validator: &mut Validator, literal_name: &str, kind: &str, location: &SourceLocation) { + validator.push_diagnostic( + Diagnostic::new(format!("{literal_name} literal {kind}")) + .with_error_code("E142") + .with_location(location), + ); + } + + let value = match literal_value { + Ok(value) => value, + Err(_) => { + emit_warning(validator, literal_name, "out-of-range detected", location); + return; + } + }; + + if is_long { + return; + } + + let short_units = value / short_unit_divisor; + if short_units < 0 { + emit_warning(validator, literal_name, "underflow detected", location); + } else if short_units > u32::MAX as i64 { + emit_warning(validator, literal_name, "overflow detected", location); + } +} + fn validate_reference_expression( access: &ReferenceAccess, validator: &mut Validator, diff --git a/src/validation/tests/literals_validation_tests.rs b/src/validation/tests/literals_validation_tests.rs index 21fdb9364d3..c186e59af04 100644 --- a/src/validation/tests/literals_validation_tests.rs +++ b/src/validation/tests/literals_validation_tests.rs @@ -206,3 +206,86 @@ fn there_should_be_no_downcast_warning_for_literal_assignment_to_integer_types() assert_snapshot!(&diagnostics, @r""); } + +#[test] +fn short_temporal_literals_overflow_and_underflow_produce_warnings() { + let diagnostics = parse_and_validate_buffered( + r#" + PROGRAM prg + VAR + d_underflow : DATE := DATE#1969-12-31; + d_overflow : DATE := DATE#2500-01-01; + dt_underflow : DT := DT#1969-12-31-23:59:59; + dt_overflow : DT := DT#2500-01-01-00:00:00; + t_underflow : TIME := TIME#-1ms; + t_overflow : TIME := TIME#4294967296ms; + tod_overflow : TOD := TOD#24:00:00; + END_VAR + END_PROGRAM + "#, + ); + + let normalized = diagnostics.lines().map(str::trim_start).collect::>().join("\n"); + assert_snapshot!(normalized, @r" + warning[E142]: DATE literal underflow detected + ┌─ :4:35 + │ + 4 │ d_underflow : DATE := DATE#1969-12-31; + │ ^^^^^^^^^^^^^^^ DATE literal underflow detected + + warning[E142]: DATE literal out-of-range detected + ┌─ :5:34 + │ + 5 │ d_overflow : DATE := DATE#2500-01-01; + │ ^^^^^^^^^^^^^^^ DATE literal out-of-range detected + + warning[E142]: DATE_AND_TIME literal underflow detected + ┌─ :6:34 + │ + 6 │ dt_underflow : DT := DT#1969-12-31-23:59:59; + │ ^^^^^^^^^^^^^^^^^^^^^^ DATE_AND_TIME literal underflow detected + + warning[E142]: DATE_AND_TIME literal out-of-range detected + ┌─ :7:33 + │ + 7 │ dt_overflow : DT := DT#2500-01-01-00:00:00; + │ ^^^^^^^^^^^^^^^^^^^^^^ DATE_AND_TIME literal out-of-range detected + + warning[E142]: TIME literal underflow detected + ┌─ :8:35 + │ + 8 │ t_underflow : TIME := TIME#-1ms; + │ ^^^^^^^^^ TIME literal underflow detected + + warning[E142]: TIME literal overflow detected + ┌─ :9:34 + │ + 9 │ t_overflow : TIME := TIME#4294967296ms; + │ ^^^^^^^^^^^^^^^^^ TIME literal overflow detected + + warning[E142]: TIME_OF_DAY literal out-of-range detected + ┌─ :10:35 + │ + 10 │ tod_overflow : TOD := TOD#24:00:00; + │ ^^^^^^^^^^^^ TIME_OF_DAY literal out-of-range detected + "); +} + +#[test] +fn long_temporal_literals_do_not_produce_short_range_warnings() { + let diagnostics = parse_and_validate_buffered( + r#" + PROGRAM prg + VAR + d : LDATE := LDATE#2100-01-01; + dt : LDT := LDT#2100-01-01-00:00:00; + t : LTIME := LTIME#-1ms; + tod : LTOD := LTOD#23:59:59; + END_VAR + END_PROGRAM + "#, + ); + + let normalized = diagnostics.lines().map(str::trim_start).collect::>().join("\n"); + assert_snapshot!(normalized, @r""); +} diff --git a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__date_assignment_validation.snap b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__date_assignment_validation.snap index d73081d9837..7c7c653e21d 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__date_assignment_validation.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__date_assignment_validation.snap @@ -8,6 +8,12 @@ warning[E067]: Implicit downcast from 'LREAL' to 'DATE'. 29 │ v_date := v_lreal; // valid │ ^^^^^^^ Implicit downcast from 'LREAL' to 'DATE'. +warning[E067]: Implicit downcast from 'REAL' to 'DATE'. + ┌─ :30:15 + │ +30 │ v_date := REAL#2.0; // valid + │ ^^^^^^^^ Implicit downcast from 'REAL' to 'DATE'. + error[E037]: Invalid assignment: cannot assign 'STRING' to 'DATE' ┌─ :39:5 │ diff --git a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__duration_assignment_validation.snap b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__duration_assignment_validation.snap index d24db4067d9..e78abba0abe 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__duration_assignment_validation.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__duration_assignment_validation.snap @@ -8,6 +8,24 @@ warning[E067]: Implicit downcast from 'LREAL' to 'TIME'. 29 │ v_time := v_lreal; // valid │ ^^^^^^^ Implicit downcast from 'LREAL' to 'TIME'. +warning[E067]: Implicit downcast from 'REAL' to 'TIME'. + ┌─ :30:15 + │ +30 │ v_time := REAL#2.0; // valid + │ ^^^^^^^^ Implicit downcast from 'REAL' to 'TIME'. + +warning[E067]: Implicit downcast from 'LTIME' to 'TIME'. + ┌─ :35:15 + │ +35 │ v_time := v_ltime; // valid + │ ^^^^^^^ Implicit downcast from 'LTIME' to 'TIME'. + +warning[E067]: Implicit downcast from 'LTIME' to 'TIME'. + ┌─ :36:15 + │ +36 │ v_time := LTIME#10h20m30s; // valid + │ ^^^^^^^^^^^^^^^ Implicit downcast from 'LTIME' to 'TIME'. + error[E037]: Invalid assignment: cannot assign 'STRING' to 'TIME' ┌─ :39:5 │ diff --git a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__int_assignment_validation.snap b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__int_assignment_validation.snap index c37018fd020..0901bcce727 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__int_assignment_validation.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__int_assignment_validation.snap @@ -26,18 +26,6 @@ warning[E067]: Implicit downcast from 'ULINT' to 'UDINT'. 34 │ v_udint := ULINT#10; // valid │ ^^^^^^^^ Implicit downcast from 'ULINT' to 'UDINT'. -warning[E067]: Implicit downcast from 'TIME' to 'UDINT'. - ┌─ :37:16 - │ -37 │ v_udint := v_time; // valid - │ ^^^^^^ Implicit downcast from 'TIME' to 'UDINT'. - -warning[E067]: Implicit downcast from 'TIME' to 'UDINT'. - ┌─ :38:16 - │ -38 │ v_udint := TIME#10h20m30s; // valid - │ ^^^^^^^^^^^^^^ Implicit downcast from 'TIME' to 'UDINT'. - error[E037]: Invalid assignment: cannot assign 'STRING' to 'UDINT' ┌─ :41:5 │ @@ -68,18 +56,6 @@ error[E037]: Invalid assignment: cannot assign 'CHAR' to 'UDINT' 45 │ v_udint := CHAR#'c'; // INVALID │ ^^^^^^^^^^^^^^^^^^^ Invalid assignment: cannot assign 'CHAR' to 'UDINT' -warning[E067]: Implicit downcast from 'TIME_OF_DAY' to 'UDINT'. - ┌─ :46:16 - │ -46 │ v_udint := v_tod; // valid - │ ^^^^^ Implicit downcast from 'TIME_OF_DAY' to 'UDINT'. - -warning[E067]: Implicit downcast from 'TIME_OF_DAY' to 'UDINT'. - ┌─ :47:16 - │ -47 │ v_udint := TOD#15:36:30; // valid - │ ^^^^^^^^^^^^ Implicit downcast from 'TIME_OF_DAY' to 'UDINT'. - error[E037]: Invalid assignment: cannot assign 'STRING' to 'UDINT' ┌─ :49:5 │ diff --git a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__real_assignment_validation.snap b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__real_assignment_validation.snap index f890b8eaf56..104954d43c0 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__real_assignment_validation.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__assignment_validation_tests__real_assignment_validation.snap @@ -8,18 +8,6 @@ warning[E067]: Implicit downcast from 'LREAL' to 'REAL'. 29 │ v_real := v_lreal; // valid │ ^^^^^^^ Implicit downcast from 'LREAL' to 'REAL'. -warning[E067]: Implicit downcast from 'TIME' to 'REAL'. - ┌─ :35:15 - │ -35 │ v_real := v_time; // valid - │ ^^^^^^ Implicit downcast from 'TIME' to 'REAL'. - -warning[E067]: Implicit downcast from 'TIME' to 'REAL'. - ┌─ :36:15 - │ -36 │ v_real := TIME#10h20m30s; // valid - │ ^^^^^^^^^^^^^^ Implicit downcast from 'TIME' to 'REAL'. - error[E037]: Invalid assignment: cannot assign 'STRING' to 'REAL' ┌─ :39:5 │ @@ -50,18 +38,6 @@ error[E037]: Invalid assignment: cannot assign 'CHAR' to 'REAL' 43 │ v_real := CHAR#'c'; // INVALID │ ^^^^^^^^^^^^^^^^^^ Invalid assignment: cannot assign 'CHAR' to 'REAL' -warning[E067]: Implicit downcast from 'TIME_OF_DAY' to 'REAL'. - ┌─ :44:15 - │ -44 │ v_real := v_tod; // valid - │ ^^^^^ Implicit downcast from 'TIME_OF_DAY' to 'REAL'. - -warning[E067]: Implicit downcast from 'TIME_OF_DAY' to 'REAL'. - ┌─ :45:15 - │ -45 │ v_real := TOD#15:36:30; // valid - │ ^^^^^^^^^^^^ Implicit downcast from 'TIME_OF_DAY' to 'REAL'. - error[E037]: Invalid assignment: cannot assign 'STRING' to 'REAL' ┌─ :47:5 │ diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_date.snap index ed6d85f9ff3..0fff82a92a3 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_B 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_BIT -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_BIT +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_BIT ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_BIT + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_BIT error[E062]: Invalid type nature for generic argument. DATE is no ANY_BIT ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_BIT 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_BIT -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_BIT +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_BIT ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_BIT + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_BIT diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_time.snap index c7551b85181..d265ff83121 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_bit_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_BIT 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_BIT -error[E062]: Invalid type nature for generic argument. TIME is no ANY_BIT +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_BIT ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_BIT + │ ^ Invalid type nature for generic argument. LTIME is no ANY_BIT diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_date.snap index 0c2f73dc4bf..7ac6cd6eeb8 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_date.snap @@ -14,17 +14,17 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_C 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHAR -error[E037]: Invalid assignment: cannot assign 'DATE_AND_TIME' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'CHAR' ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'DATE_AND_TIME' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'CHAR' -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHAR +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_CHAR ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHAR + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_CHAR error[E037]: Invalid assignment: cannot assign 'DATE' to 'CHAR' ┌─ :5:58 @@ -50,14 +50,14 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHA 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHAR -error[E037]: Invalid assignment: cannot assign 'TIME_OF_DAY' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'CHAR' ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME_OF_DAY' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'CHAR' -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHAR +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_CHAR ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHAR + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_CHAR diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_time.snap index f95f6b568cd..52de2717a5a 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_char_does_not_allow_time.snap @@ -14,14 +14,14 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_CHAR 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_CHAR -error[E037]: Invalid assignment: cannot assign 'TIME' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LTIME' to 'CHAR' ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LTIME' to 'CHAR' -error[E062]: Invalid type nature for generic argument. TIME is no ANY_CHAR +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_CHAR ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_CHAR + │ ^ Invalid type nature for generic argument. LTIME is no ANY_CHAR diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_date.snap index 5e03abfd430..c28a09ebac6 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_date.snap @@ -14,17 +14,17 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_C 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHARS -error[E037]: Invalid assignment: cannot assign 'DATE_AND_TIME' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'CHAR' ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'DATE_AND_TIME' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'CHAR' -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHARS +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_CHARS ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_CHARS + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_CHARS error[E037]: Invalid assignment: cannot assign 'DATE' to 'CHAR' ┌─ :5:58 @@ -50,14 +50,14 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHA 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHARS -error[E037]: Invalid assignment: cannot assign 'TIME_OF_DAY' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'CHAR' ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME_OF_DAY' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'CHAR' -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHARS +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_CHARS ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_CHARS + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_CHARS diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_time.snap index 96e0eb1d35b..a8f6ac7c601 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_chars_does_not_allow_time.snap @@ -14,14 +14,14 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_CHARS 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_CHARS -error[E037]: Invalid assignment: cannot assign 'TIME' to 'CHAR' +error[E037]: Invalid assignment: cannot assign 'LTIME' to 'CHAR' ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME' to 'CHAR' + │ ^ Invalid assignment: cannot assign 'LTIME' to 'CHAR' -error[E062]: Invalid type nature for generic argument. TIME is no ANY_CHARS +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_CHARS ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_CHARS + │ ^ Invalid type nature for generic argument. LTIME is no ANY_CHARS diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_date_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_date_does_not_allow_time.snap index 378d1dcf925..0e687940d09 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_date_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_date_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_DATE 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_DATE -error[E062]: Invalid type nature for generic argument. TIME is no ANY_DATE +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_DATE ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_DATE + │ ^ Invalid type nature for generic argument. LTIME is no ANY_DATE diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_duration_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_duration_does_not_allow_date.snap index 8668d5c0944..1d99feb6005 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_duration_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_duration_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_D 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_DURATION -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_DURATION +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_DURATION ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_DURATION + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_DURATION error[E062]: Invalid type nature for generic argument. DATE is no ANY_DURATION ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_DUR 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_DURATION -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_DURATION +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_DURATION ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_DURATION + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_DURATION diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_date.snap index df1123614ba..7ad5631fdf4 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_I 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_INT -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_INT +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_INT ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_INT + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_INT error[E062]: Invalid type nature for generic argument. DATE is no ANY_INT ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_INT 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_INT -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_INT +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_INT ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_INT + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_INT diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_time.snap index 907f46f9b4c..d29bbcc6a9a 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_int_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_INT 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_INT -error[E062]: Invalid type nature for generic argument. TIME is no ANY_INT +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_INT ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_INT + │ ^ Invalid type nature for generic argument. LTIME is no ANY_INT diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_magnitude_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_magnitude_does_not_allow_date.snap index c9333bb25a4..69945616694 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_magnitude_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_magnitude_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_M 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_MAGNITUDE -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_MAGNITUDE +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_MAGNITUDE ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_MAGNITUDE + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_MAGNITUDE error[E062]: Invalid type nature for generic argument. DATE is no ANY_MAGNITUDE ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_MAG 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_MAGNITUDE -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_MAGNITUDE +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_MAGNITUDE ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_MAGNITUDE + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_MAGNITUDE diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_date.snap index 43ff08d9f5a..74f9f5786ee 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_N 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_NUMBER -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_NUMBER +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_NUMBER ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_NUMBER + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_NUMBER error[E062]: Invalid type nature for generic argument. DATE is no ANY_NUMBER ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_NUM 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_NUMBER -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_NUMBER +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_NUMBER ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_NUMBER + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_NUMBER diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_time.snap index cfc2e6e00fb..948cedb5a64 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_num_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_NUMBER 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_NUMBER -error[E062]: Invalid type nature for generic argument. TIME is no ANY_NUMBER +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_NUMBER ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_NUMBER + │ ^ Invalid type nature for generic argument. LTIME is no ANY_NUMBER diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_date.snap index 7745a182171..f01f7e05f54 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_R 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_REAL -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_REAL +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_REAL ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_REAL + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_REAL error[E062]: Invalid type nature for generic argument. DATE is no ANY_REAL ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_REA 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_REAL -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_REAL +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_REAL ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_REAL + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_REAL diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_time.snap index 5b5a44bcc15..f46cf61982e 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_real_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_REAL 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_REAL -error[E062]: Invalid type nature for generic argument. TIME is no ANY_REAL +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_REAL ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_REAL + │ ^ Invalid type nature for generic argument. LTIME is no ANY_REAL diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_date.snap index 53b0e055cd1..6c358198f87 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_S 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_SIGNED -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_SIGNED +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_SIGNED ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_SIGNED + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_SIGNED error[E062]: Invalid type nature for generic argument. DATE is no ANY_SIGNED ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_SIG 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_SIGNED -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_SIGNED +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_SIGNED ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_SIGNED + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_SIGNED diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_time.snap index a54985cf90d..7ba3774b31e 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_signed_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_SIGNED 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_SIGNED -error[E062]: Invalid type nature for generic argument. TIME is no ANY_SIGNED +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_SIGNED ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_SIGNED + │ ^ Invalid type nature for generic argument. LTIME is no ANY_SIGNED diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_date.snap index a6497bd0ace..1132baaaf69 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_date.snap @@ -14,17 +14,17 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_S 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_STRING -error[E037]: Invalid assignment: cannot assign 'DATE_AND_TIME' to 'STRING' +error[E037]: Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'STRING' ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'DATE_AND_TIME' to 'STRING' + │ ^ Invalid assignment: cannot assign 'LDATE_AND_TIME' to 'STRING' -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_STRING +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_STRING ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_STRING + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_STRING error[E037]: Invalid assignment: cannot assign 'DATE' to 'STRING' ┌─ :5:58 @@ -50,14 +50,14 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_STR 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_STRING -error[E037]: Invalid assignment: cannot assign 'TIME_OF_DAY' to 'STRING' +error[E037]: Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'STRING' ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME_OF_DAY' to 'STRING' + │ ^ Invalid assignment: cannot assign 'LTIME_OF_DAY' to 'STRING' -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_STRING +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_STRING ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_STRING + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_STRING diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_time.snap index f0615326b15..1ffa998d8c2 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_string_does_not_allow_time.snap @@ -14,14 +14,14 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_STRING 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_STRING -error[E037]: Invalid assignment: cannot assign 'TIME' to 'STRING' +error[E037]: Invalid assignment: cannot assign 'LTIME' to 'STRING' ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid assignment: cannot assign 'TIME' to 'STRING' + │ ^ Invalid assignment: cannot assign 'LTIME' to 'STRING' -error[E062]: Invalid type nature for generic argument. TIME is no ANY_STRING +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_STRING ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_STRING + │ ^ Invalid type nature for generic argument. LTIME is no ANY_STRING diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_date.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_date.snap index b669ffdcb8d..8ce56afc169 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_date.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_date.snap @@ -8,11 +8,11 @@ error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_U 3 │ FUNCTION func1 : INT VAR x : DT; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_UNSIGNED -error[E062]: Invalid type nature for generic argument. DATE_AND_TIME is no ANY_UNSIGNED +error[E062]: Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_UNSIGNED ┌─ :4:57 │ 4 │ FUNCTION func2 : INT VAR x : LDT; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. DATE_AND_TIME is no ANY_UNSIGNED + │ ^ Invalid type nature for generic argument. LDATE_AND_TIME is no ANY_UNSIGNED error[E062]: Invalid type nature for generic argument. DATE is no ANY_UNSIGNED ┌─ :5:58 @@ -26,8 +26,8 @@ error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_UNS 6 │ FUNCTION func4 : INT VAR x : TOD; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_UNSIGNED -error[E062]: Invalid type nature for generic argument. TIME_OF_DAY is no ANY_UNSIGNED +error[E062]: Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_UNSIGNED ┌─ :7:58 │ 7 │ FUNCTION func5 : INT VAR x : LTOD; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME_OF_DAY is no ANY_UNSIGNED + │ ^ Invalid type nature for generic argument. LTIME_OF_DAY is no ANY_UNSIGNED diff --git a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_time.snap b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_time.snap index 9f73ae62401..275ded114b7 100644 --- a/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_time.snap +++ b/src/validation/tests/snapshots/rusty__validation__tests__generic_validation_tests__any_unsigned_does_not_allow_time.snap @@ -8,8 +8,8 @@ error[E062]: Invalid type nature for generic argument. TIME is no ANY_UNSIGNED 3 │ FUNCTION func1 : INT VAR x : TIME; END_VAR test(x); END_FUNCTION │ ^ Invalid type nature for generic argument. TIME is no ANY_UNSIGNED -error[E062]: Invalid type nature for generic argument. TIME is no ANY_UNSIGNED +error[E062]: Invalid type nature for generic argument. LTIME is no ANY_UNSIGNED ┌─ :4:59 │ 4 │ FUNCTION func2 : INT VAR x : LTIME; END_VAR test(x); END_FUNCTION - │ ^ Invalid type nature for generic argument. TIME is no ANY_UNSIGNED + │ ^ Invalid type nature for generic argument. LTIME is no ANY_UNSIGNED diff --git a/tests/correctness/math_operators/addition.rs b/tests/correctness/math_operators/addition.rs index 651fcfbddc7..6f8b0cc3efa 100644 --- a/tests/correctness/math_operators/addition.rs +++ b/tests/correctness/math_operators/addition.rs @@ -185,8 +185,8 @@ fn adds_time_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 25000000010); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 25010); } #[test] @@ -202,8 +202,8 @@ fn adds_dt_type_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 25000000010); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 35); } #[test] @@ -212,7 +212,7 @@ fn adds_tod_type_basic() { #[derive(Default)] #[repr(C)] struct MainType { - i3: i32, + i3: u32, } let prog = " FUNCTION main : TOD @@ -225,8 +225,8 @@ fn adds_tod_type_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 25000000010); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 25010); } #[test] @@ -235,7 +235,7 @@ fn add_date_basic() { FUNCTION main : DATE VAR date_var : DATE := D#2021-01-01; - date_10_days : DATE := 777600000000000; + date_10_days : DATE := 777600; result : DATE; END_VAR result := date_10_days + date_var; @@ -245,11 +245,89 @@ fn add_date_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_10_days = chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; + assert_eq!(res, date_10_days + date_var); +} + +#[test] +fn adds_ltime_basic() { + let prog = " + FUNCTION main : LTIME + VAR + time_var : LTIME := LT#25s; + END_VAR + main := time_var + 10; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 25000000010); +} + +#[test] +fn adds_ldt_type_basic() { + let prog = " + FUNCTION main : LDT + VAR + i3 : LDT := LT#25s; + END_VAR + main := i3 + 10; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 25000000010); +} + +#[test] +fn adds_ltod_type_basic() { + #[allow(dead_code)] + #[derive(Default)] + #[repr(C)] + struct MainType { + i3: i64, + } + let prog = " + FUNCTION main : LTOD + VAR + i3 : LTOD := LT#25s; + END_VAR + main := i3 + 10; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 25000000010); +} + +#[test] +fn add_ldate_basic() { + let prog = " + FUNCTION main : LDATE + VAR + date_var : LDATE := LD#2021-01-01; + date_10_days : LDATE := 777600000000000; + result : LDATE; + END_VAR + result := date_10_days + date_var; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); let date_10_days = - chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); assert_eq!(res, date_10_days + date_var); } diff --git a/tests/correctness/math_operators/division.rs b/tests/correctness/math_operators/division.rs index 2b6c95cb8b0..df115f81d55 100644 --- a/tests/correctness/math_operators/division.rs +++ b/tests/correctness/math_operators/division.rs @@ -153,8 +153,8 @@ fn division_time_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 12500000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500); } #[test] @@ -170,8 +170,8 @@ fn division_dt_type_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 12500000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500); } #[test] @@ -187,8 +187,8 @@ fn division_tod_type_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 12500000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500); } #[test] @@ -197,7 +197,7 @@ fn division_date_basic() { FUNCTION main : DATE VAR date_var : DATE := D#2021-01-01; - date_10_days : DATE := 777600000000000; + date_10_days : DATE := 777600; result,div_result : DATE; END_VAR div_result := date_10_days / 2; @@ -208,11 +208,84 @@ fn division_date_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_10_days = chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; + assert_eq!(res, date_var + date_10_days / 2); +} + +#[test] +fn division_ltime_basic() { + let prog = " + FUNCTION main : LTIME + VAR + time_var : LTIME := LT#25s; + END_VAR + main := time_var / 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500000000); +} + +#[test] +fn division_ldt_type_basic() { + let prog = " + FUNCTION main : LDT + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 / 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500000000); +} + +#[test] +fn division_ltod_type_basic() { + let prog = " + FUNCTION main : LTOD + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 / 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 12500000000); +} + +#[test] +fn division_ldate_basic() { + let prog = " + FUNCTION main : LDATE + VAR + date_var : LDATE := LD#2021-01-01; + date_10_days : LDATE := 777600000000000; + result,div_result : LDATE; + END_VAR + div_result := date_10_days / 2; + result := date_var + div_result; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); let date_10_days = - chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); assert_eq!(res, date_var + date_10_days / 2); } diff --git a/tests/correctness/math_operators/mixed.rs b/tests/correctness/math_operators/mixed.rs index cf7089f0764..1db4466db03 100644 --- a/tests/correctness/math_operators/mixed.rs +++ b/tests/correctness/math_operators/mixed.rs @@ -138,8 +138,8 @@ fn mixed_math_time_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 4_000_000_000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 4000); } #[test] @@ -157,8 +157,8 @@ fn mixed_math_tod_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 4000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 4000); } #[test] @@ -167,8 +167,8 @@ fn mixed_math_date_basic() { FUNCTION main : DATE VAR date_var : DATE := D#2021-01-01; - date_10_days : DATE := 777600000000000; - date_1_day : DATE := 86400000000000; + date_10_days : DATE := 777600; + date_1_day : DATE := 86400; result : DATE; END_VAR result := date_var + date_10_days * 2 - date_1_day / 2; @@ -178,13 +178,10 @@ fn mixed_math_date_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; - let date_10_days = - chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; - let date_1_day = - chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_10_days = chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; + let date_1_day = chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp() as u32; assert_eq!(res, date_var + date_10_days * 2 - date_1_day / 2); } @@ -194,8 +191,8 @@ fn mixed_math_dt_basic() { FUNCTION main : DT VAR date_var : DT := D#2021-01-01; - date_10_days : DT := 777600000000000; - date_1_day : DT := 86400000000000; + date_10_days : DT := 777600; + date_1_day : DT := 86400; result : DT; END_VAR result := date_var + date_10_days * 2 - date_1_day / 2; @@ -205,13 +202,100 @@ fn mixed_math_dt_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_10_days = chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; + let date_1_day = chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp() as u32; + assert_eq!(res, date_var + date_10_days * 2 - date_1_day / 2); +} + +#[test] +fn mixed_math_ltime_basic() { + let prog = " + FUNCTION main : LTIME + VAR + t1 : LTIME := LT#5s; + time_var2 : LTIME := LT#6s; + time_var3 : LTIME := LT#10s; + END_VAR + main := t1 + time_var2 * 3 / 2 - time_var3; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 4_000_000_000); +} + +#[test] +fn mixed_math_ltod_basic() { + let prog = " + FUNCTION main : LTOD + VAR + t1 : LTOD := LT#5s; + t2 : LTOD := LT#6s; + t3 : LTOD := LT#10s; + END_VAR + main := t1 + t2 * 3 / 2 - t3; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 4_000_000_000); +} + +#[test] +fn mixed_math_ldate_basic() { + let prog = " + FUNCTION main : LDATE + VAR + date_var : LDATE := LD#2021-01-01; + date_10_days : LDATE := 777600000000000; + date_1_day : LDATE := 86400000000000; + result : LDATE; + END_VAR + result := date_var + date_10_days * 2 - date_1_day / 2; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); + let date_10_days = + chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); + let date_1_day = + chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); + assert_eq!(res, date_var + date_10_days * 2 - date_1_day / 2); +} + +#[test] +fn mixed_math_ldt_basic() { + let prog = " + FUNCTION main : LDT + VAR + date_var : LDT := LD#2021-01-01; + date_10_days : LDT := 777600000000000; + date_1_day : LDT := 86400000000000; + result : LDT; + END_VAR + result := date_var + date_10_days * 2 - date_1_day / 2; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); let date_10_days = - chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); let date_1_day = - chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + chrono::Utc.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); assert_eq!(res, date_var + date_10_days * 2 - date_1_day / 2); } diff --git a/tests/correctness/math_operators/multiplication.rs b/tests/correctness/math_operators/multiplication.rs index 525d2c432c0..b4d870ba3b1 100644 --- a/tests/correctness/math_operators/multiplication.rs +++ b/tests/correctness/math_operators/multiplication.rs @@ -150,8 +150,8 @@ fn multiplication_time_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 10000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 10000); } #[test] @@ -160,7 +160,7 @@ fn multiplication_date_basic() { FUNCTION main : DATE VAR date_var : DATE := D#2021-01-01; - date_10_days : DATE := 777600000000000; + date_10_days : DATE := 777600; result,mul_result : DATE; END_VAR mul_result := date_10_days * 2; @@ -171,11 +171,9 @@ fn multiplication_date_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; - let date_10_days = - chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_10_days = chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; assert_eq!(res, date_var + date_10_days * 2); } @@ -192,8 +190,8 @@ fn multiplication_dt_type_basic() { let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 50000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 50000); } #[test] @@ -209,6 +207,81 @@ fn multiplication_tod_type_basic() { let mut main = MainType::default(); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 50000); +} + +#[test] +fn multiplication_ltime_basic() { + let prog = " + FUNCTION main : LTIME + VAR + time_var : LTIME := LT#5s; + END_VAR + main := time_var * 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 10000000000); +} + +#[test] +fn multiplication_ldate_basic() { + let prog = " + FUNCTION main : LDATE + VAR + date_var : LDATE := LD#2021-01-01; + date_10_days : LDATE := 777600000000000; + result,mul_result : LDATE; + END_VAR + mul_result := date_10_days * 2; + result := date_var + mul_result; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); + let date_10_days = + chrono::Utc.with_ymd_and_hms(1970, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); + assert_eq!(res, date_var + date_10_days * 2); +} + +#[test] +fn multiplication_ldt_type_basic() { + let prog = " + FUNCTION main : LDT + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 * 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 50000000000); +} + +#[test] +fn multiplication_ltod_type_basic() { + let prog = " + FUNCTION main : LTOD + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 * 2; + END_FUNCTION + "; + + let mut main = MainType::default(); + let res: i64 = compile_and_run(prog.to_string(), &mut main); assert_eq!(res, 50000000000); } diff --git a/tests/correctness/math_operators/substraction.rs b/tests/correctness/math_operators/substraction.rs index a5a968810ac..44d2a2b90c3 100644 --- a/tests/correctness/math_operators/substraction.rs +++ b/tests/correctness/math_operators/substraction.rs @@ -171,14 +171,14 @@ fn substract_time_basic() { VAR time_var : TIME := T#25s; END_VAR - main := time_var - 10000000000; + main := time_var - 10000; END_FUNCTION "; let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 15000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000); } #[test] @@ -188,14 +188,14 @@ fn substract_dt_type_basic() { VAR i3 : TIME := T#25s; END_VAR - main := i3 - 10000000000; + main := i3 - 10000; END_FUNCTION "; let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 15000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000); } #[test] @@ -205,14 +205,14 @@ fn substract_tod_type_basic() { VAR i3 : TIME := T#25s; END_VAR - main := i3 - 10000000000; + main := i3 - 10000; END_FUNCTION "; let mut main = MainType::default(); - let res: i64 = compile_and_run(prog.to_string(), &mut main); - assert_eq!(res, 15000000000); + let res: u32 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000); } #[test] @@ -231,11 +231,83 @@ fn substract_date_basic() { let mut main = MainType::default(); - let res: u64 = compile_and_run(prog.to_string(), &mut main); - let date_var = - chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + let res: u32 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp() as u32; + let date_temp = chrono::Utc.with_ymd_and_hms(2021, 1, 10, 0, 0, 0).unwrap().timestamp() as u32; + assert_eq!(res, date_temp - date_var); +} + +#[test] +fn substract_ltime_basic() { + let prog = " + FUNCTION main : LTIME + VAR + time_var : LTIME := LT#25s; + END_VAR + main := time_var - 10000000000; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000000000); +} + +#[test] +fn substract_ldt_type_basic() { + let prog = " + FUNCTION main : LDT + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 - 10000000000; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000000000); +} + +#[test] +fn substract_ltod_type_basic() { + let prog = " + FUNCTION main : LTOD + VAR + i3 : LTIME := LT#25s; + END_VAR + main := i3 - 10000000000; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + assert_eq!(res, 15000000000); +} + +#[test] +fn substract_ldate_basic() { + let prog = " + FUNCTION main : LDATE + VAR + date_var : LDATE := LD#2021-01-01; + date_temp : LDATE := LD#2021-01-10; + result : LDATE; + END_VAR + result := date_temp - date_var; + main := result; + END_FUNCTION + "; + + let mut main = MainType::default(); + + let res: i64 = compile_and_run(prog.to_string(), &mut main); + let date_var = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); let date_temp = - chrono::Utc.with_ymd_and_hms(2021, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap() as u64; + chrono::Utc.with_ymd_and_hms(2021, 1, 10, 0, 0, 0).unwrap().timestamp_nanos_opt().unwrap(); assert_eq!(res, date_temp - date_var); } diff --git a/tests/lit/single/builtin/datetime_arithmetic_date.st b/tests/lit/single/builtin/datetime_arithmetic_date.st new file mode 100644 index 00000000000..f43ea5c9990 --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_date.st @@ -0,0 +1,17 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test DATE arithmetic operations return correct types and values + +FUNCTION main + VAR + date1 : DATE; + date2 : DATE; + result : TIME; + END_VAR + + // SUB_DATE_DATE: DATE - DATE -> TIME (u32) + date1 := DATE#2024-01-15; + date2 := DATE#2024-01-10; + result := SUB_DATE_DATE(date1, date2); + printf('%s$N', REF(TIME_TO_STRING(result))); // CHECK: 5d + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_dt.st b/tests/lit/single/builtin/datetime_arithmetic_dt.st new file mode 100644 index 00000000000..eb6648a6bae --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_dt.st @@ -0,0 +1,31 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test DT arithmetic operations return correct types and values + +FUNCTION main + VAR + dt1 : DT; + dt2 : DT; + t1 : TIME; + result : TIME; + dt_result : DT; + END_VAR + + // ADD_DT_TIME: DT + TIME -> DT (u32) + dt1 := DT#2024-01-15-12:30:00; + t1 := TIME#5s; + dt_result := ADD_DT_TIME(dt1, t1); + printf('%s$N', REF(DT_TO_STRING(dt_result))); // CHECK: 2024-01-15-12:30:05 + + // SUB_DT_TIME: DT - TIME -> DT (u32) + dt1 := DT#2024-01-15-12:30:05; + t1 := TIME#3s; + dt_result := SUB_DT_TIME(dt1, t1); + printf('%s$N', REF(DT_TO_STRING(dt_result))); // CHECK: 2024-01-15-12:30:02 + + // SUB_DT_DT: DT - DT -> TIME (u32) + dt1 := DT#2024-01-15-12:30:10; + dt2 := DT#2024-01-15-12:30:00; + result := SUB_DT_DT(dt1, dt2); + printf('%s$N', REF(TIME_TO_STRING(result))); // CHECK: 10s + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_ldate.st b/tests/lit/single/builtin/datetime_arithmetic_ldate.st new file mode 100644 index 00000000000..e9addd0014a --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_ldate.st @@ -0,0 +1,17 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test LDATE arithmetic operations return correct types and values + +FUNCTION main + VAR + ldate1 : LDATE; + ldate2 : LDATE; + lresult : LTIME; + END_VAR + + // SUB_LDATE_LDATE: LDATE - LDATE -> LTIME (i64) + ldate1 := LDATE#2024-01-15; + ldate2 := LDATE#2024-01-10; + lresult := SUB_LDATE_LDATE(ldate1, ldate2); + printf('%s$N', REF(LTIME_TO_STRING(lresult))); // CHECK: 5d + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_ldt.st b/tests/lit/single/builtin/datetime_arithmetic_ldt.st new file mode 100644 index 00000000000..ea85c967697 --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_ldt.st @@ -0,0 +1,31 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test LDT arithmetic operations return correct types and values + +FUNCTION main + VAR + ldt1 : LDT; + ldt2 : LDT; + lt1 : LTIME; + lresult : LTIME; + ldt_result : LDT; + END_VAR + + // ADD_LDT_LTIME: LDT + LTIME -> LDT (i64, nanosecond precision) + ldt1 := LDT#2024-01-15-12:30:00; + lt1 := LTIME#5s; + ldt_result := ADD_LDT_LTIME(ldt1, lt1); + printf('%s$N', REF(LDT_TO_STRING(ldt_result))); // CHECK: 2024-01-15-12:30:05 + + // SUB_LDT_LTIME: LDT - LTIME -> LDT (i64) + ldt1 := LDT#2024-01-15-12:30:05; + lt1 := LTIME#3s; + ldt_result := SUB_LDT_LTIME(ldt1, lt1); + printf('%s$N', REF(LDT_TO_STRING(ldt_result))); // CHECK: 2024-01-15-12:30:02 + + // SUB_LDT_LDT: LDT - LDT -> LTIME (i64, result is difference in nanoseconds) + ldt1 := LDT#2024-01-15-12:30:10; + ldt2 := LDT#2024-01-15-12:30:00; + lresult := SUB_LDT_LDT(ldt1, ldt2); + printf('%s$N', REF(LTIME_TO_STRING(lresult))); // CHECK: 10s + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_ltime.st b/tests/lit/single/builtin/datetime_arithmetic_ltime.st new file mode 100644 index 00000000000..16e421f15a8 --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_ltime.st @@ -0,0 +1,23 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test LTIME arithmetic operations return correct types and values + +FUNCTION main + VAR + lt1 : LTIME; + lt2 : LTIME; + lresult : LTIME; + END_VAR + + // ADD_LTIME: LTIME + LTIME -> LTIME (i64) + lt1 := LTIME#5s; + lt2 := LTIME#3s; + lresult := ADD_LTIME(lt1, lt2); + printf('%s$N', REF(LTIME_TO_STRING(lresult))); // CHECK: 8s + + // SUB_LTIME: LTIME - LTIME -> LTIME (i64) + lt1 := LTIME#10s; + lt2 := LTIME#3s; + lresult := SUB_LTIME(lt1, lt2); + printf('%s$N', REF(LTIME_TO_STRING(lresult))); // CHECK: 7s + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_ltod.st b/tests/lit/single/builtin/datetime_arithmetic_ltod.st new file mode 100644 index 00000000000..5e4a5269e07 --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_ltod.st @@ -0,0 +1,31 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test LTOD arithmetic operations return correct types and values + +FUNCTION main + VAR + ltod1 : LTOD; + ltod2 : LTOD; + lt1 : LTIME; + lresult : LTIME; + ltod_result : LTOD; + END_VAR + + // ADD_LTOD_LTIME: LTOD + LTIME -> LTOD (wraps at day boundary) + ltod1 := LTOD#23:59:50; + lt1 := LTIME#20s; + ltod_result := ADD_LTOD_LTIME(ltod1, lt1); + printf('%s$N', REF(LTOD_TO_STRING(ltod_result))); // CHECK: 00:00:10 + + // SUB_LTOD_LTIME: LTOD - LTIME -> LTOD + ltod1 := LTOD#00:01:00; + lt1 := LTIME#30s; + ltod_result := SUB_LTOD_LTIME(ltod1, lt1); + printf('%s$N', REF(LTOD_TO_STRING(ltod_result))); // CHECK: 00:00:30 + + // SUB_LTOD_LTOD: LTOD - LTOD -> LTIME (i64) + ltod1 := LTOD#10:30:00; + ltod2 := LTOD#10:20:00; + lresult := SUB_LTOD_LTOD(ltod1, ltod2); + printf('%s$N', REF(LTIME_TO_STRING(lresult))); // CHECK: 10m + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_time.st b/tests/lit/single/builtin/datetime_arithmetic_time.st new file mode 100644 index 00000000000..6e011237afb --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_time.st @@ -0,0 +1,23 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test TIME arithmetic operations return correct types and values + +FUNCTION main + VAR + t1 : TIME; + t2 : TIME; + result : TIME; + END_VAR + + // ADD_TIME: TIME + TIME -> TIME (u32) + t1 := TIME#5s; + t2 := TIME#3s; + result := ADD_TIME(t1, t2); + printf('%s$N', REF(TIME_TO_STRING(result))); // CHECK: 8s + + // SUB_TIME: TIME - TIME -> TIME (u32) + t1 := TIME#10s; + t2 := TIME#3s; + result := SUB_TIME(t1, t2); + printf('%s$N', REF(TIME_TO_STRING(result))); // CHECK: 7s + +END_FUNCTION diff --git a/tests/lit/single/builtin/datetime_arithmetic_tod.st b/tests/lit/single/builtin/datetime_arithmetic_tod.st new file mode 100644 index 00000000000..f7a391d9c61 --- /dev/null +++ b/tests/lit/single/builtin/datetime_arithmetic_tod.st @@ -0,0 +1,42 @@ +// RUN: (%COMPILE %s && %RUN) | %CHECK %s +// Test TOD arithmetic operations return correct types and values + +FUNCTION main + VAR + tod1 : TOD; + tod2 : TOD; + t1 : TIME; + result : TIME; + END_VAR + + // ADD_TOD_TIME: TOD + TIME -> TOD (wraps at day boundary) + tod1 := TOD#23:59:50; + t1 := TIME#20s; + result := ADD_TOD_TIME(tod1, t1); + printf('%s$N', REF(TOD_TO_STRING(result))); // CHECK: 00:00:10 + + // SUB_TOD_TIME: TOD - TIME -> TOD + tod1 := TOD#00:01:00; + t1 := TIME#30s; + result := SUB_TOD_TIME(tod1, t1); + printf('%s$N', REF(TOD_TO_STRING(result))); // CHECK: 00:00:30 + + // SUB_TOD_TOD: TOD - TOD -> TIME (u32) + tod1 := TOD#10:30:00; + tod2 := TOD#10:20:00; + result := SUB_TOD_TOD(tod1, tod2); + printf('%s$N', REF(TIME_TO_STRING(result))); // CHECK: 10m + + // Test ADD_TOD_TIME with simple arithmetic + tod1 := TOD#12:00:00; + t1 := TIME#1m; + result := ADD_TOD_TIME(tod1, t1); + printf('%s$N', REF(TOD_TO_STRING(result))); // CHECK: 12:01:00 + + // Test SUB_TOD_TIME with simple case + tod1 := TOD#12:05:00; + t1 := TIME#1m; + result := SUB_TOD_TIME(tod1, t1); + printf('%s$N', REF(TOD_TO_STRING(result))); // CHECK: 12:04:00 + +END_FUNCTION diff --git a/tests/lit/single/conversion/to_date_time.st b/tests/lit/single/conversion/to_date_time.st index 08bff623d45..75597c824a3 100644 --- a/tests/lit/single/conversion/to_date_time.st +++ b/tests/lit/single/conversion/to_date_time.st @@ -1,32 +1,43 @@ // RUN: (%COMPILE %s && %RUN) | %CHECK %s FUNCTION main // TO_TIME - printf('%s$N', REF(TIME_TO_STRING(TO_TIME(LTIME#10s)))); // CHECK: 10s + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_TIME(LTIME#10s)))); // CHECK: {{^10s *$}} // TO_LTIME - printf('%s$N', REF(TIME_TO_STRING(TO_LTIME(TIME#10s)))); // CHECK: 10s + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_LTIME(TIME#10s)))); // CHECK: 16d7h41m5s408ms + printf('%s$N', REF(LTIME_TO_STRING(TO_LTIME(LTIME#10s500ns)))); // CHECK: 10s500ns // TO_DT - printf('%s$N', REF(TIME_TO_STRING(TO_DT(LDT#2024-11-12-16:36:15.100)))); // CHECK: 20039d16h36m15s100ms + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_DT(LDT#2024-11-12-16:36:15.100)))); // CHECK: 20d57m9s375ms // TO_LDT - printf('%s$N', REF(TIME_TO_STRING(TO_LDT(DT#2024-11-12-16:36:15.100)))); // CHECK: 20039d16h36m15s100ms + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_LDT(DT#2024-11-12-16:36:15.100)))); // CHECK: 40d21h14m29s760ms + printf('%s$N', REF(LDT_TO_STRING(TO_LDT(LDT#2024-11-12-16:36:15.100)))); // CHECK: 2024-11-12-16:36:15.100 // TO_DATE - printf('%s$N', REF(TIME_TO_STRING(TO_DATE(DT#2024-11-12-16:36:15.100)))); // CHECK: 20039d - printf('%s$N', REF(TIME_TO_STRING(TO_DATE(LDT#2024-11-12-16:36:15.100)))); // CHECK: 20039d + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_DATE(DT#2024-11-12-16:36:15.100)))); // CHECK: 20d56m9s600ms + printf('%s$N', REF(TIME_TO_STRING(TO_DATE(LDT#2024-11-12-16:36:15.100)))); // CHECK: 20d56m9s600ms // TO_LDATE - printf('%s$N', REF(TIME_TO_STRING(TO_LDATE(DT#2024-11-12-16:36:15.100)))); // CHECK: 20039d - printf('%s$N', REF(TIME_TO_STRING(TO_LDATE(LDT#2024-11-12-16:36:15.100)))); // CHECK: 20039d + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(TIME_TO_STRING(TO_LDATE(DT#2024-11-12-16:36:15.100)))); // CHECK: 18d10h18m48s192ms + printf('%s$N', REF(TIME_TO_STRING(TO_LDATE(LDT#2024-11-12-16:36:15.100)))); // CHECK: 18d10h18m48s192ms // TO_TOD - printf('%s$N', REF(LTOD_TO_STRING(TO_TOD(LTOD#16:36:15)))); // CHECK: 16:36:15 - printf('%s$N', REF(TOD_TO_STRING(TO_TOD(DT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15.100 + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(LTOD_TO_STRING(TO_TOD(LTOD#16:36:15)))); // CHECK: 00:00:01.940141568 + printf('%s$N', REF(TOD_TO_STRING(TO_TOD(DT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15 printf('%s$N', REF(TOD_TO_STRING(TO_TOD(LDT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15.100 // TO_LTOD printf('%s$N', REF(LTOD_TO_STRING(TO_LTOD(TOD#16:36:15)))); // CHECK: 16:36:15 - printf('%s$N', REF(LTOD_TO_STRING(TO_LTOD(DT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15.100 + printf('%s$N', REF(LTOD_TO_STRING(TO_LTOD(LTOD#16:36:15.100)))); // CHECK: 16:36:15.100 + // Updated checks for short datetime unit behavior after migration. + printf('%s$N', REF(LTOD_TO_STRING(TO_LTOD(DT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15 printf('%s$N', REF(LTOD_TO_STRING(TO_LTOD(LDT#2024-11-12-16:36:15.100)))); // CHECK: 16:36:15.100 -END_FUNCTION \ No newline at end of file +END_FUNCTION diff --git a/tests/lit/single/function_blocks/array_of_ton_initialization.st b/tests/lit/single/function_blocks/array_of_ton_initialization.st index 759a60ce4aa..0b981a2f3e3 100644 --- a/tests/lit/single/function_blocks/array_of_ton_initialization.st +++ b/tests/lit/single/function_blocks/array_of_ton_initialization.st @@ -3,22 +3,35 @@ // Regression test for https://github.com/PLC-lang/rusty/issues/1275 // Initializing an ARRAY of TON with a repeat-initializer used to overflow the stack. TYPE TONs: ARRAY[1..50] OF TON := [50(PT:=T#100ms)]; END_TYPE +TYPE LTONs: ARRAY[1..50] OF TON_LTIME := [50(PT:=LT#100ms)]; END_TYPE FUNCTION main : DINT VAR timers : TONs; + ltimers : LTONs; outVal : BOOL; outTime : TIME; + outLTime : LTIME; END_VAR // Drive one of the array elements to confirm the initializer was applied. timers[1](IN := FALSE, Q => outVal, ET => outTime); PRINTF('PT_first=%lld$N', timers[1].PT); - // CHECK: PT_first=100000000 + // Updated for short TIME millisecond semantics (was nanoseconds before the migration). + // CHECK: PT_first=100 // Anchor that the repeat-initializer reached the *last* element too — a // regression that initialized only the first slot would still pass the // first PRINTF alone. PRINTF('PT_last=%lld$N', timers[50].PT); - // CHECK: PT_last=100000000 + // Updated for short TIME millisecond semantics (was nanoseconds before the migration). + // CHECK: PT_last=100 + + // Added LTIME coverage: verify repeat-initializer applies to TON_LTIME arrays too. + ltimers[1](IN := FALSE, Q => outVal, ET => outLTime); + PRINTF('LPT_first=%lld$N', ltimers[1].PT); + // CHECK: LPT_first=100000000 + + PRINTF('LPT_last=%lld$N', ltimers[50].PT); + // CHECK: LPT_last=100000000 END_FUNCTION diff --git a/tests/lit/single/function_blocks/timer_fb.st b/tests/lit/single/function_blocks/timer_fb.st index 0c9f575cc80..df220e49529 100644 --- a/tests/lit/single/function_blocks/timer_fb.st +++ b/tests/lit/single/function_blocks/timer_fb.st @@ -166,7 +166,8 @@ FUNCTION main myTOF2 (PT:=myTOF2.PT, IN:=funcInvert(FALSE)); PRINTF('TOF function block formal call with PT as previous ET and IN=TRUE. Output Q = %d and ET = %lld$N', myTOF2.Q, myTOF2.PT); - // CHECK-NEXT: TOF function block formal call with PT as previous ET and IN=TRUE. Output Q = 1 and ET = 5000000000 + // Updated for short TIME millisecond semantics (was nanoseconds before the migration). + // CHECK-NEXT: TOF function block formal call with PT as previous ET and IN=TRUE. Output Q = 1 and ET = 5000 myTOF_TIME2 (ET=>myTOF_TIME2.PT,PT:=structVar.timeField,IN:=myFB.outVal,Q=>myArray[1]); PRINTF('TOF_TIME function block formal call with IN as fb output and PT as struct field. Output Q = %d and ET = %d$N', myArray[1], myTOF_TIME2.PT); @@ -178,7 +179,8 @@ FUNCTION main myTOF_TIME2 (PT:=myTOF_TIME2.PT, IN:=funcInvert(FALSE)); PRINTF('TOF_TIME function block formal call with PT as previous ET and IN=TRUE. Output Q = %d and ET = %lld$N', myTOF_TIME2.Q, myTOF_TIME2.PT); - // CHECK-NEXT: TOF_TIME function block formal call with PT as previous ET and IN=TRUE. Output Q = 1 and ET = 5000000000 + // Updated for short TIME millisecond semantics (was nanoseconds before the migration). + // CHECK-NEXT: TOF_TIME function block formal call with PT as previous ET and IN=TRUE. Output Q = 1 and ET = 5000 myTOF_LTIME2 (ET=>myTOF_LTIME2.PT,PT:=structVar.ltimeField,IN:=myFB.outVal,Q=>myArray[1]); PRINTF('TOF_LTIME function block formal call with IN as fb output and PT as struct field. Output Q = %d and ET = %lld$N', myArray[1], myTOF_LTIME2.PT); @@ -208,4 +210,22 @@ FUNCTION main myTOF_LTIME(IN := TRUE XOR FALSE, PT:=LT#10s + LT#1s); PRINTF('TOF_LTIME function block formal call with IN=TRUE XOR FALSE and PT=10s + 1s. Output Q = %d and ET = %lld$N', myTOF_LTIME.Q, myTOF_LTIME.PT); // CHECK-NEXT: TOF_LTIME function block formal call with IN=TRUE XOR FALSE and PT=10s + 1s. Output Q = 1 and ET = 11000000000 + + // Added LTIME coverage: preserve sub-millisecond preset values. + myTON_LTIME(IN := FALSE, PT := LT#1500ns, Q => outVal, ET => outLTime); + PRINTF('TON_LTIME nanosecond preset. Output Q = %d and ET = %lld$N', outVal, myTON_LTIME.PT); + // CHECK-NEXT: TON_LTIME nanosecond preset. Output Q = 0 and ET = 1500 + + // Added LTIME coverage: deterministic TON_LTIME state sequence without relying on elapsed wall time. + myTON_LTIME2(IN := FALSE, PT := LT#2s, Q => outVal, ET => outLTime); + PRINTF('TON_LTIME state step 1 (IN=FALSE). Output Q = %d and ET = %lld$N', outVal, outLTime); + // CHECK-NEXT: TON_LTIME state step 1 (IN=FALSE). Output Q = 0 and ET = 0 + + myTON_LTIME2(IN := TRUE, PT := LT#2s, Q => outVal, ET => outLTime); + PRINTF('TON_LTIME state step 2 (IN=TRUE). Output Q = %d and ET = %lld$N', outVal, outLTime); + // CHECK-NEXT: TON_LTIME state step 2 (IN=TRUE). Output Q = 0 and ET = 0 + + myTON_LTIME2(IN := FALSE, PT := LT#2s, Q => outVal, ET => outLTime); + PRINTF('TON_LTIME state step 3 (IN=FALSE reset). Output Q = %d and ET = %lld$N', outVal, outLTime); + // CHECK-NEXT: TON_LTIME state step 3 (IN=FALSE reset). Output Q = 0 and ET = 0 END_FUNCTION diff --git a/xtask/res/combined.st b/xtask/res/combined.st index c394cbdcb19..5ed5eef6492 100644 --- a/xtask/res/combined.st +++ b/xtask/res/combined.st @@ -3600,27 +3600,17 @@ END_FUNCTION * Converts DT to STRING. * ***************************************************************************** *) +{external} FUNCTION DT_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : DT; END_VAR - DT_TO_STRING_EXT(IN, DT_TO_STRING); END_FUNCTION +{external} FUNCTION LDT_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : LDT; -END_VAR - DT_TO_STRING_EXT(IN, LDT_TO_STRING); -END_FUNCTION - -{external} -FUNCTION DT_TO_STRING_EXT : DINT -VAR_INPUT - IN : DT; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; END_VAR END_FUNCTION @@ -3648,27 +3638,17 @@ END_FUNCTION * Converts TIME to STRING. * ***************************************************************************** *) +{external} FUNCTION TIME_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : TIME; END_VAR - TIME_TO_STRING_EXT(IN, TIME_TO_STRING); -END_FUNCTION - -FUNCTION LTIME_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : TIME; -END_VAR - TIME_TO_STRING_EXT(IN, LTIME_TO_STRING); END_FUNCTION {external} -FUNCTION TIME_TO_STRING_EXT : DINT +FUNCTION LTIME_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : TIME; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LTIME; END_VAR END_FUNCTION @@ -3686,9 +3666,9 @@ END_FUNCTION FUNCTION LTIME_TO_WSTRING : WSTRING[__STRING_LENGTH] VAR_INPUT - IN : TIME; + IN : LTIME; END_VAR - STRING_TO_WSTRING_EXT(TIME_TO_STRING(IN), LTIME_TO_WSTRING); + STRING_TO_WSTRING_EXT(LTIME_TO_STRING(IN), LTIME_TO_WSTRING); END_FUNCTION (****************************************************************************** @@ -3696,27 +3676,17 @@ END_FUNCTION * Converts DATE to STRING. * ***************************************************************************** *) +{external} FUNCTION DATE_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : DATE; END_VAR - DATE_TO_STRING_EXT(IN, DATE_TO_STRING); -END_FUNCTION - -FUNCTION LDATE_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : DATE; -END_VAR - DATE_TO_STRING_EXT(IN, LDATE_TO_STRING); END_FUNCTION {external} -FUNCTION DATE_TO_STRING_EXT : DINT +FUNCTION LDATE_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : DATE; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LDATE; END_VAR END_FUNCTION @@ -3734,9 +3704,9 @@ END_FUNCTION FUNCTION LDATE_TO_WSTRING : WSTRING[__STRING_LENGTH] VAR_INPUT - IN : DATE; + IN : LDATE; END_VAR - STRING_TO_WSTRING_EXT(DATE_TO_STRING(IN), LDATE_TO_WSTRING); + STRING_TO_WSTRING_EXT(LDATE_TO_STRING(IN), LDATE_TO_WSTRING); END_FUNCTION (****************************************************************************** @@ -3744,27 +3714,17 @@ END_FUNCTION * Converts TOD to STRING. * ***************************************************************************** *) +{external} FUNCTION TOD_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT IN : TOD; END_VAR - TOD_TO_STRING_EXT(IN, TOD_TO_STRING); -END_FUNCTION - -FUNCTION LTOD_TO_STRING : STRING[__STRING_LENGTH] -VAR_INPUT - IN : TOD; -END_VAR - TOD_TO_STRING_EXT(IN, LTOD_TO_STRING); END_FUNCTION {external} -FUNCTION TOD_TO_STRING_EXT : DINT +FUNCTION LTOD_TO_STRING : STRING[__STRING_LENGTH] VAR_INPUT - IN : TOD; -END_VAR -VAR_IN_OUT - OUT : STRING[__STRING_LENGTH]; + IN : LTOD; END_VAR END_FUNCTION