Skip to content

Commit a66637a

Browse files
authored
Merge pull request #31 from engineerjoe440/enhancement/#15-add-support-for-64-bit-LTIME-type
ENH: LTIME, LDATE_AND_TIME, LTIME_OF_DAY support
2 parents db9986b + 39bb4d2 commit a66637a

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

blark/iec.lark

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,29 @@ DOUBLE_BYTE_CHARACTER_STRING: "\"" DOUBLE_BYTE_CHARACTER* "\""
110110

111111
// B.1.2.3
112112
?time_literal: duration
113+
| lduration
113114
| time_of_day
114115
| date
115116
| date_and_time
116117

117118
// B.1.2.3.1
118119
duration: ( "TIME"i | "T"i ) "#" [ MINUS ] _interval
120+
lduration: ( "LTIME"i | "LT"i ) "#" [ MINUS ] _linterval
119121

120122
_interval: days
121123
| hours
122124
| minutes
123125
| seconds
124126
| milliseconds
125127

128+
_linterval: days
129+
| hours
130+
| minutes
131+
| seconds
132+
| milliseconds
133+
| microseconds
134+
| nanoseconds
135+
126136
days: FIXED_POINT "d"i
127137
| INTEGER "d"i "_"? hours
128138
| INTEGER "d"i
@@ -142,16 +152,24 @@ seconds: FIXED_POINT "s"i
142152
milliseconds: FIXED_POINT "ms"i
143153
| INTEGER "ms"i
144154

155+
microseconds: FIXED_POINT "us"i
156+
| INTEGER "us"i
157+
158+
nanoseconds: FIXED_POINT "ns"i
159+
| INTEGER "ns"i
160+
145161
// B.1.2.3.2
146162
_daytime: day_hour ":" day_minute ":" day_second
147163

148164
time_of_day: ("TIME_OF_DAY"i | "TOD"i) "#" _daytime
165+
ltime_of_day: ("LTIME_OF_DAY"i | "LTOD"i) "#" _daytime
149166

150167
?day_hour: INTEGER
151168
?day_minute: INTEGER
152169
?day_second: FIXED_POINT
153170

154171
date: ( "DATE"i | "D"i | "d"i ) "#" _date_literal
172+
ldate: "LDATE"i "#" _date_literal
155173

156174
_date_literal: year "-" month "-" day
157175

@@ -160,6 +178,7 @@ _date_literal: year "-" month "-" day
160178
?day: INTEGER
161179

162180
date_and_time: ( "DATE_AND_TIME"i | "DT"i ) "#" _date_literal "-" _daytime
181+
ldate_and_time: ( "LDATE_AND_TIME"i | "LDT"i ) "#" _date_literal "-" _daytime
163182

164183
// B.1.3
165184
non_generic_type_name: [ pointer_type ] ( elementary_type_name | derived_type_name | DOTTED_IDENTIFIER )
@@ -169,6 +188,10 @@ TYPE_TOD: "TIME_OF_DAY"i
169188
| "TOD"i
170189
TYPE_DATETIME: "DATE_AND_TIME"i
171190
| "DT"i
191+
TYPE_LTOD: "LTIME_OF_DAY"i
192+
| "LTOD"i
193+
TYPE_LDATETIME: "LDATE_AND_TIME"i
194+
| "LDT"i
172195

173196
?elementary_type_name: NUMERIC_TYPE_NAME
174197
| DATE_TYPE_NAME
@@ -197,8 +220,12 @@ REAL_TYPE_NAME: "REAL"i
197220

198221
DATE_TYPE_NAME: TYPE_TOD
199222
| TYPE_DATETIME
223+
| TYPE_LTOD
224+
| TYPE_LDATETIME
200225
| "DATE"i
226+
| "LDATE"i
201227
| "TIME"i
228+
| "LTIME"i
202229

203230
BIT_STRING_TYPE_NAME: "BOOL"i
204231
| "BYTE"i

blark/tests/test_transformer.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def test_check_unhandled_rules(grammar):
6363
"hours",
6464
"seconds",
6565
"milliseconds",
66+
"microseconds",
67+
"nanoseconds",
6668
"minutes",
6769

6870
# handled as aliases
@@ -117,6 +119,20 @@ def test_check_unhandled_rules(grammar):
117119
param("duration", "T#1D1H1M1S1MS", tf.Duration(days="1", hours="1", minutes="1", seconds="1", milliseconds="1")), # noqa: E501
118120
param("duration", "TIME#1H1M1S1MS", tf.Duration(hours="1", minutes="1", seconds="1", milliseconds="1")), # noqa: E501
119121
param("time_of_day", "TIME_OF_DAY#1:1:1.2", tf.TimeOfDay(hour="1", minute="1", second="1.2")), # noqa: E501
122+
param("lduration", "LTIME#-1D", tf.Lduration(days="1", negative=True)),
123+
param("lduration", "LTIME#1D", tf.Lduration(days="1")),
124+
param("lduration", "LTIME#10S", tf.Lduration(seconds="10")),
125+
param("lduration", "LTIME#1H", tf.Lduration(hours="1")),
126+
param("lduration", "LTIME#1M", tf.Lduration(minutes="1")),
127+
param("lduration", "LTIME#10MS", tf.Lduration(milliseconds="10")),
128+
param("lduration", "LTIME#1.1D", tf.Lduration(days="1.1")),
129+
param("lduration", "LTIME#10.1S", tf.Lduration(seconds="10.1")),
130+
param("lduration", "LTIME#1.1H", tf.Lduration(hours="1.1")),
131+
param("lduration", "LTIME#1.1M", tf.Lduration(minutes="1.1")),
132+
param("lduration", "LTIME#10.1MS", tf.Lduration(milliseconds="10.1")),
133+
param("lduration", "LT#1D1H1M1S1MS", tf.Lduration(days="1", hours="1", minutes="1", seconds="1", milliseconds="1")), # noqa: E501
134+
param("lduration", "LTIME#1H1M1S1MS", tf.Lduration(hours="1", minutes="1", seconds="1", milliseconds="1")), # noqa: E501
135+
param("ltime_of_day", "LTIME_OF_DAY#1:1:1.2", tf.LtimeOfDay(hour="1", minute="1", second="1.2")), # noqa: E501
120136
],
121137
)
122138
def test_literal(name, value, expected):
@@ -159,6 +175,8 @@ def test_literal(name, value, expected):
159175
param("time_of_day", "TIME_OF_DAY#1:1:1.2"),
160176
param("date", "DATE#1970-1-1"),
161177
param("date_and_time", "DT#1970-1-1-1:2:30.3"),
178+
param("ldate", "LDATE#1970-1-1"),
179+
param("ldate_and_time", "LDT#1970-1-1-1:2:30.300123456"),
162180
param("single_byte_string_spec", "STRING[1]"),
163181
param("single_byte_string_spec", "STRING(1)"),
164182
param("single_byte_string_spec", "STRING(1) := 'abc'"),

blark/transform.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,54 @@ def __str__(self):
415415
return f"TIME#{self.value}"
416416

417417

418+
@dataclass
419+
@_rule_handler("lduration")
420+
class Lduration(Literal):
421+
"""Long duration literal value."""
422+
423+
days: Optional[lark.Token] = None
424+
hours: Optional[lark.Token] = None
425+
minutes: Optional[lark.Token] = None
426+
seconds: Optional[lark.Token] = None
427+
milliseconds: Optional[lark.Token] = None
428+
microseconds: Optional[lark.Token] = None
429+
nanoseconds: Optional[lark.Token] = None
430+
negative: bool = False
431+
meta: Optional[Meta] = meta_field()
432+
433+
@staticmethod
434+
def from_lark(minus: Optional[lark.Token], interval: lark.Tree) -> Lduration:
435+
kwargs = typing.cast(
436+
Dict[str, lark.Token],
437+
{
438+
tree.data: tree.children[0]
439+
for tree in interval.iter_subtrees()
440+
}
441+
)
442+
return Lduration(**kwargs, negative=minus is not None, meta=None)
443+
444+
@property
445+
def value(self) -> str:
446+
"""The long duration value."""
447+
prefix = "-" if self.negative else ""
448+
return prefix + "".join(
449+
f"{value}{suffix}"
450+
for value, suffix in (
451+
(self.days, "D"),
452+
(self.hours, "H"),
453+
(self.minutes, "M"),
454+
(self.seconds, "S"),
455+
(self.milliseconds, "MS"),
456+
(self.microseconds, "US"),
457+
(self.nanoseconds, "NS"),
458+
)
459+
if value is not None
460+
)
461+
462+
def __str__(self):
463+
return f"LTIME#{self.value}"
464+
465+
418466
@dataclass
419467
@_rule_handler("time_of_day")
420468
class TimeOfDay(Literal):
@@ -433,6 +481,24 @@ def __str__(self):
433481
return f"TIME_OF_DAY#{self.value}"
434482

435483

484+
@dataclass
485+
@_rule_handler("ltime_of_day")
486+
class LtimeOfDay(Literal):
487+
"""Long time of day literal value."""
488+
hour: lark.Token
489+
minute: lark.Token
490+
second: lark.Token
491+
meta: Optional[Meta] = meta_field()
492+
493+
@property
494+
def value(self) -> str:
495+
"""The long time of day value."""
496+
return f"{self.hour}:{self.minute}:{self.second}"
497+
498+
def __str__(self):
499+
return f"LTIME_OF_DAY#{self.value}"
500+
501+
436502
@dataclass
437503
@_rule_handler("date")
438504
class Date(Literal):
@@ -452,6 +518,25 @@ def __str__(self):
452518
return f"DATE#{self.value}"
453519

454520

521+
@dataclass
522+
@_rule_handler("ldate")
523+
class Ldate(Literal):
524+
"""Long date literal value."""
525+
526+
year: lark.Token
527+
month: lark.Token
528+
day: lark.Token
529+
meta: Optional[Meta] = meta_field()
530+
531+
@property
532+
def value(self) -> str:
533+
"""The long time of day value."""
534+
return f"{self.year}-{self.month}-{self.day}"
535+
536+
def __str__(self):
537+
return f"LDATE#{self.value}"
538+
539+
455540
@dataclass
456541
@_rule_handler("date_and_time")
457542
class DateTime(Literal):
@@ -484,6 +569,38 @@ def __str__(self):
484569
return f"DT#{self.value}"
485570

486571

572+
@dataclass
573+
@_rule_handler("ldate_and_time")
574+
class LdateTime(Literal):
575+
"""Long date and time literal value."""
576+
577+
ldate: Ldate
578+
ltime: LtimeOfDay
579+
meta: Optional[Meta] = meta_field()
580+
581+
@staticmethod
582+
def from_lark(
583+
year: lark.Token,
584+
month: lark.Token,
585+
day: lark.Token,
586+
hour: lark.Token,
587+
minute: lark.Token,
588+
second: lark.Token,
589+
) -> LdateTime:
590+
return LdateTime(
591+
ldate=Ldate(year=year, month=month, day=day),
592+
ltime=LtimeOfDay(hour=hour, minute=minute, second=second),
593+
)
594+
595+
@property
596+
def value(self) -> str:
597+
"""The time of day value."""
598+
return f"{self.ldate.value}-{self.ltime.value}"
599+
600+
def __str__(self):
601+
return f"LDT#{self.value}"
602+
603+
487604
@dataclass
488605
@_rule_handler("string_literal")
489606
class String(Literal):

0 commit comments

Comments
 (0)