Skip to content

Commit

Permalink
review improvements of DATE types
Browse files Browse the repository at this point in the history
  • Loading branch information
riederm committed May 6, 2021
1 parent 07cb7cd commit dd703a5
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 193 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty"
version = "0.1.0"
version = "0.2.0"
authors = ["Ghaith Hachem <ghaith.hachem@gmail.com>", "Mathias Rieder <mathias.rieder@gmail.com>"]
edition = "2018"
readme = "README.md"
Expand Down
2 changes: 2 additions & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
- [Multiple Files]()
- [Libraries]()
- [Using in external programs]()

- [Datatypes](./datatypes.md)
61 changes: 61 additions & 0 deletions book/src/datatypes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Datatypes

## Date and Time
### 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 milliseconds and denotes the number of milliseconds
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`.

Example literals
- `d1 : DATE := DATE#2021-05-02;`
- `d2 : DATE := DATE#1-12-24;`
- `d3 : DATE := D#2000-1-1;`

### 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 milliseconds and denotes the
number of milliseconds 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`.

Note that only the seconds-segment can have a fraction denoting the milliseconds.

Example literals
- `d1 : DATE_AND_TIME := DATE_AND_TIME#2021-05-02-14:20:10.25;`
- `d2 : DATE_AND_TIME := DATE_AND_TIME#1-12-24-00:00:1;`
- `d3 : DATE_AND_TIME := DT#1999-12-31-23:59:59.999;`

### 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 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.

Example literals
- `t1 : TIME_OF_DAY := TIME_OF_DAY#14:20:10.25;`
- `t2 : TIME_OF_DAY := TIME_OF_DY#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. Supported segements 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 `TIME` literal can have a fraction.

Example literals
- `t1 : TIME := TIME#2d4h6m8s10ms;`
- `t2 : TIME := T#2d4.2h;`
- `t3 : TIME := T#-10s4ms16ns;`
9 changes: 9 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ pub enum Statement {
min: f64,
sec: f64,
milli: f64,
micro: f64,
nano: u32,
negative: bool,
location: SourceRange,
},
LiteralReal {
Expand Down Expand Up @@ -573,6 +576,9 @@ impl Debug for Statement {
min,
sec,
milli,
micro,
nano,
negative,
..
} => f
.debug_struct("LiteralTime")
Expand All @@ -581,6 +587,9 @@ impl Debug for Statement {
.field("min", min)
.field("sec", sec)
.field("milli", milli)
.field("micro", micro)
.field("nano", nano)
.field("negative", negative)
.finish(),
Statement::LiteralReal { value, .. } => {
f.debug_struct("LiteralReal").field("value", value).finish()
Expand Down
34 changes: 27 additions & 7 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,11 +1136,18 @@ impl<'a, 'b> ExpressionCodeGenerator<'a, 'b> {
min,
sec,
milli,
micro,
nano,
negative,
..
} => self.llvm.create_const_int(
self.index,
&Some(self.llvm.i64_type().into()),
format!("{}", calculate_time_micro(*day, *hour, *min, *sec, *milli)).as_str(),
format!(
"{}",
calculate_time_nano(*negative, calculate_dhm_time_seconds(*day, *hour, *min, *sec), *milli, *micro, *nano)
)
.as_str(),
),
Statement::LiteralReal { value, .. } => {
self.llvm
Expand Down Expand Up @@ -1433,14 +1440,27 @@ impl<'a, 'b> ExpressionCodeGenerator<'a, 'b> {
Ok((target_type, phi_value.as_basic_value()))
}
}

fn calculate_time_micro(day: f64, hour: f64, min: f64, sec: f64, milli: f64) -> i64 {

/// calculates the seconds in the given days, hours minutes and seconds
fn calculate_dhm_time_seconds(day: f64, hour: f64, min: f64, sec: f64) -> f64 {
let hours = day * 24_f64 + hour;
let mins = hours * 60_f64 + min;
let secs = mins * 60_f64 + sec;
let millis = secs * 1000_f64 + milli;
let mins = hours * 60_f64 + min;
mins * 60_f64 + sec
}

/// calculates the nanos in the given seconds, millis, micros and nano/**
fn calculate_time_nano(negative: bool, sec: f64, milli: f64, micro: f64, nano: u32) -> i64 {
let millis = sec * 1000_f64 + milli;
let micro = millis * 1000_f64 + micro;
let nano = micro * 1000_f64 + nano as f64;
//go to full micro
(millis * 1000_f64).round() as i64
let nanos = (nano).round() as i64;

if negative {
-nanos
} else {
nanos
}
}

/// calculates the milliseconds since 1970-01-01-00:00:00 for the given
Expand Down
38 changes: 24 additions & 14 deletions src/codegen/tests/code_gen_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ END_VAR
y := DATE#1984-10-01;
y := D#1970-01-01;
z := DATE_AND_TIME#1984-10-01-20:15:14;
z := DT#1970-01-01-16:20:04;
z := DT#1970-01-01-16:20:04.123;
z := DT#1970-01-01-16:20:04.123456789;
END_PROGRAM
"#
);
Expand All @@ -323,7 +324,8 @@ entry:
store i64 465436800000, i64* %y, align 4
store i64 0, i64* %y, align 4
store i64 465509714000, i64* %z, align 4
store i64 58804000, i64* %z, align 4
store i64 58804123, i64* %z, align 4
store i64 58804123, i64* %z, align 4
ret void
}
"#;
Expand All @@ -341,8 +343,12 @@ y : TIME;
END_VAR
y := T#0d0h0m0s0ms;
y := T#0.5d;
y := T#0d0h0m0s1ms;
y := T#1d0h0m0s1ms;
y := T#0d0h0m0.1s;
y := T#0d0h0m100ms;
y := T#1ms;
y := T#-1us;
y := T#1ns;
y := T#-1d0h0m0s1ms;
y := T#100d0h0m0s1ms;
END_PROGRAM
"#
Expand All @@ -359,10 +365,14 @@ define void @prg(%prg_interface* %0) {
entry:
%y = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 0
store i64 0, i64* %y, align 4
store i64 43200000000, i64* %y, align 4
store i64 1000, i64* %y, align 4
store i64 86400001000, i64* %y, align 4
store i64 8640000001000, i64* %y, align 4
store i64 43200000000000, i64* %y, align 4
store i64 100000000, i64* %y, align 4
store i64 100000000, i64* %y, align 4
store i64 1000000, i64* %y, align 4
store i64 -1000, i64* %y, align 4
store i64 1, i64* %y, align 4
store i64 -86400001000000, i64* %y, align 4
store i64 8640000001000000, i64* %y, align 4
ret void
}
"#;
Expand Down Expand Up @@ -408,7 +418,7 @@ entry:
}

#[test]
fn time_variables_have_micro_seconds_resolution(){
fn time_variables_have_nano_seconds_resolution(){
let result = codegen!(
r#"PROGRAM prg
VAR
Expand All @@ -418,7 +428,7 @@ END_VAR
y := T#1ms;
y := T#0.000001s;
y := T#0.0000001s;
y := T#100d0h0m0s1.123ms;
y := T#100d0h0m0s1.125ms;
END_PROGRAM
"#
);
Expand All @@ -433,10 +443,10 @@ source_filename = "main"
define void @prg(%prg_interface* %0) {
entry:
%y = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 0
store i64 1000000, i64* %y, align 4
store i64 1000, i64* %y, align 4
store i64 1, i64* %y, align 4
store i64 0, i64* %y, align 4
store i64 8640000001123, i64* %y, align 4
store i64 100, i64* %y, align 4
store i64 8640000001125000, i64* %y, align 4
ret void
}
"#;
Expand Down Expand Up @@ -473,7 +483,7 @@ fn date_comparisons() {
%load_b = load i64, i64* %b, align 4
%tmpVar1 = icmp sgt i64 %load_b, 1619897357000
%load_c = load i64, i64* %c, align 4
%tmpVar2 = icmp sgt i64 %load_c, 156557000000
%tmpVar2 = icmp sgt i64 %load_c, 156557000000000
%load_d = load i64, i64* %d, align 4
%tmpVar3 = icmp sgt i64 %load_d, 70157000
ret void
Expand Down
6 changes: 3 additions & 3 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,13 +344,13 @@ pub enum Token {
#[regex("D(ATE)?#\\d+-\\d+-\\d+")]
LiteralDate,

#[regex("(DATE_AND_TIME|DT)#\\d+-\\d+-\\d+-\\d+:\\d+:\\d+(.\\d)?")]
#[regex("(DATE_AND_TIME|DT)#\\d+-\\d+-\\d+-\\d+:\\d+:\\d+(\\.\\d+)?")]
LiteralDateAndTime,

#[regex("(TIME_OF_DAY|TOD)#\\d+:\\d+:\\d+(.\\d+)?")]
#[regex("(TIME_OF_DAY|TOD)#\\d+:\\d+:\\d+(\\.\\d+)?")]
LiteralTimeOfDay,

#[regex("(T(IME)?|t(ime)?)#(\\d+(.\\d+)?(d|h|ms|m|s))+")]
#[regex("T(IME)?#-?(\\d+(\\.\\d+)?(d|h|ms|m|s|us|ns))+")]
LiteralTime,

#[regex("'((\\$.)|[^$'])*'")]
Expand Down
25 changes: 17 additions & 8 deletions src/lexer/tests/lexer_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,20 @@ fn real_literals_test() {

#[test]
fn date_literals_test() {
let mut lexer = lex("DATE#1984-10-01 D#1-1-1");
assert_eq!(lexer.token, LiteralDate);
lexer.advance();
assert_eq!(lexer.token, LiteralDate);
lexer.advance();
let mut lexer = lex(r#"
DATE#1984-10-01 D#1-1-1
DATE#1946 D#2001.10.04
DATE#1946-4 D#-1-1-1
"#);
for _ in 1..=2 {
assert_eq!(lexer.token, LiteralDate);
lexer.advance();
}

for _ in 1..=4 {
assert_ne!(lexer.token, LiteralDate);
lexer.advance();
}
}

#[test]
Expand Down Expand Up @@ -298,9 +307,9 @@ fn time_of_day_literals_test() {
#[test]
fn time_literals_test() {
let mut lexer = lex(r#"
t#12d t#13h time#14m TIME#15s t#16ms
t#12d10ms T#12h10m time#12m4s
TIME#4d6h8m7s12ms
T#12d T#13h TIME#14m TIME#15s T#16ms
T#12d10ms T#12h10m TIME#12m4s3ns
TIME#4d6h8m7s12ms04us2ns
"#);
for _ in 1..9 {
assert_eq!(
Expand Down
Loading

0 comments on commit dd703a5

Please sign in to comment.