mirror of
https://github.com/status-im/NimYAML.git
synced 2025-01-12 12:34:23 +00:00
Implemented !!timestamp
This commit is contained in:
parent
05c4aa733c
commit
64f68ae1af
@ -5,7 +5,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
import "../yaml"
|
||||
import unittest, strutils, streams, tables
|
||||
import unittest, strutils, streams, tables, times
|
||||
|
||||
type
|
||||
MyTuple = tuple
|
||||
@ -208,6 +208,14 @@ suite "Serialization":
|
||||
var output = dump(input, tsNone, asTidy, blockOnly)
|
||||
assertStringEqual yamlDirs & "\n!n!nil:string \"\"", output
|
||||
|
||||
test "Load timestamps":
|
||||
let input = "[2001-12-15T02:59:43.1Z, 2001-12-14t21:59:43.10-05:00, 2001-12-14 21:59:43.10-5]"
|
||||
var result: seq[Time]
|
||||
load(input, result)
|
||||
assert result.len() == 3
|
||||
# currently, there is no good way of checking the result content, because
|
||||
# the parsed Time may have any timezone offset.
|
||||
|
||||
test "Load string sequence":
|
||||
let input = newStringStream(" - a\n - b")
|
||||
var result: seq[string]
|
||||
|
101
yaml/hints.nim
101
yaml/hints.nim
@ -33,10 +33,11 @@ type
|
||||
## ``yTypeBoolTrue`` ``y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON``
|
||||
## ``yTypeBoolFalse`` ``n|N|no|No|NO|false|False|FALSE|off|Off|OFF``
|
||||
## ``yTypeNull`` ``~ | null | Null | NULL``
|
||||
## ``yTypeTimestamp`` see `here <http://yaml.org/type/timestamp.html>`_.
|
||||
## ``yTypeUnknown`` ``*``
|
||||
## ================== =========================
|
||||
yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue,
|
||||
yTypeBoolFalse, yTypeNull, yTypeUnknown
|
||||
yTypeBoolFalse, yTypeNull, yTypeUnknown, yTypeTimestamp
|
||||
|
||||
YamlTypeHintState = enum
|
||||
ythInitial,
|
||||
@ -59,7 +60,16 @@ type
|
||||
|
||||
ythPointLowerIN, ythPointLowerN, ythPointLowerNA,
|
||||
|
||||
ythMinus, yth0, ythInt, ythDecimal, ythNumE, ythNumEPlusMinus, ythExponent
|
||||
ythMinus, yth0, ythInt1, ythInt1Zero, ythInt2, ythInt2Zero, ythInt3,
|
||||
ythInt3Zero, ythInt4, ythInt4Zero, ythInt,
|
||||
ythDecimal, ythNumE, ythNumEPlusMinus, ythExponent,
|
||||
|
||||
ythYearMinus, ythMonth1, ythMonth2, ythMonthMinus, ythMonthMinusNoYmd,
|
||||
ythDay1, ythDay1NoYmd, ythDay2, ythDay2NoYmd,
|
||||
ythAfterDayT, ythAfterDaySpace, ythHour1, ythHour2, ythHourColon,
|
||||
ythMinute1, ythMinute2, ythMinuteColon, ythSecond1, ythSecond2, ythFraction,
|
||||
ythAfterTimeSpace, ythAfterTimeZ, ythAfterTimePlusMinus, ythTzHour1,
|
||||
ythTzHour2, ythTzHourColon, ythTzMinute1, ythTzMinute2
|
||||
|
||||
macro typeHintStateMachine(c: untyped, content: untyped): typed =
|
||||
yAssert content.kind == nnkStmtList
|
||||
@ -101,20 +111,78 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
||||
typeHintStateMachine ch:
|
||||
of '~': ythInitial => ythNULL
|
||||
of '.':
|
||||
[yth0, ythInt] => ythDecimal
|
||||
[yth0, ythInt1, ythInt2, ythInt3, ythInt4, ythInt] => ythDecimal
|
||||
[ythInitial, ythMinus] => ythPoint
|
||||
of '+': ythNumE => ythNumEPlusMinus
|
||||
ythSecond2 => ythFraction
|
||||
of '+':
|
||||
ythNumE => ythNumEPlusMinus
|
||||
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
||||
of '-':
|
||||
ythInitial => ythMinus
|
||||
ythNumE => ythNumEPlusMinus
|
||||
ythInitial => ythMinus
|
||||
ythNumE => ythNumEPlusMinus
|
||||
[ythInt4, ythInt4Zero] => ythYearMinus
|
||||
ythMonth1 => ythMonthMinusNoYmd
|
||||
ythMonth2 => ythMonthMinus
|
||||
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
||||
of ':':
|
||||
[ythHour1, ythHour2] => ythHourColon
|
||||
ythMinute2 => ythMinuteColon
|
||||
[ythTzHour1, ythTzHour2] => ythTzHourColon
|
||||
of '0':
|
||||
[ythInitial, ythMinus] => yth0
|
||||
ythInitial => ythInt1Zero
|
||||
ythMinus => yth0
|
||||
[ythNumE, ythNumEPlusMinus] => ythExponent
|
||||
[ythInt, ythDecimal, ythExponent] => nil
|
||||
ythInt1 => ythInt2
|
||||
ythInt1Zero => ythInt2Zero
|
||||
ythInt2 => ythInt3
|
||||
ythInt2Zero => ythInt3Zero
|
||||
ythInt3 => ythInt4
|
||||
ythInt3Zero => ythInt4Zero
|
||||
ythInt4 => ythInt
|
||||
ythYearMinus => ythMonth1
|
||||
ythMonth1 => ythMonth2
|
||||
ythMonthMinus => ythDay1
|
||||
ythMonthMinusNoYmd => ythDay1NoYmd
|
||||
ythDay1 => ythDay2
|
||||
ythDay1NoYmd => ythDay2NoYmd
|
||||
[ythAfterDaySpace, ythAfterDayT] => ythHour1
|
||||
ythHour1 => ythHour2
|
||||
ythHourColon => ythMinute1
|
||||
ythMinute1 => ythMinute2
|
||||
ythMinuteColon => ythSecond1
|
||||
ythSecond1 => ythSecond2
|
||||
ythAfterTimePlusMinus => ythTzHour1
|
||||
ythTzHour1 => ythTzHour2
|
||||
ythTzHourColon => ythTzMinute1
|
||||
ythTzMinute1 => ythTzMinute2
|
||||
[ythInt, ythDecimal, ythExponent, ythFraction] => nil
|
||||
of '1'..'9':
|
||||
[ythInitial, ythMinus] => ythInt
|
||||
ythInitial => ythInt1
|
||||
ythInt1 => ythInt2
|
||||
ythInt1Zero => ythInt2Zero
|
||||
ythInt2 => ythInt3
|
||||
ythInt2Zero => ythInt3Zero
|
||||
ythInt3 => ythInt4
|
||||
ythInt3Zero => ythInt4Zero
|
||||
[ythInt4, ythMinus] => ythInt
|
||||
[ythNumE, ythNumEPlusMinus] => ythExponent
|
||||
[ythInt, ythDecimal, ythExponent] => nil
|
||||
ythYearMinus => ythMonth1
|
||||
ythMonth1 => ythMonth2
|
||||
ythMonthMinus => ythDay1
|
||||
ythMonthMinusNoYmd => ythDay1NoYmd
|
||||
ythDay1 => ythDay2
|
||||
ythDay1NoYmd => ythDay2NoYmd
|
||||
[ythAfterDaySpace, ythAfterDayT] => ythHour1
|
||||
ythHour1 => ythHour2
|
||||
ythHourColon => ythMinute1
|
||||
ythMinute1 => ythMinute2
|
||||
ythMinuteColon => ythSecond1
|
||||
ythSecond1 => ythSecond2
|
||||
ythAfterTimePlusMinus => ythTzHour1
|
||||
ythTzHour1 => ythTzHour2
|
||||
ythTzHourColon => ythTzMinute1
|
||||
ythTzMinute1 => ythTzMinute2
|
||||
[ythInt, ythDecimal, ythExponent, ythFraction] => nil
|
||||
of 'a':
|
||||
ythF => ythLowerFA
|
||||
ythPointN => ythPointNA
|
||||
@ -174,7 +242,9 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
||||
of 'S':
|
||||
ythFAL => ythFALS
|
||||
ythYE => ythYES
|
||||
of 't', 'T': ythInitial => ythT
|
||||
of 't', 'T':
|
||||
ythInitial => ythT
|
||||
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT
|
||||
of 'u':
|
||||
ythN => ythLowerNU
|
||||
ythLowerTR => ythLowerTRU
|
||||
@ -182,6 +252,11 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
||||
ythN => ythNU
|
||||
ythTR => ythTRU
|
||||
of 'y', 'Y': ythInitial => ythY
|
||||
of 'Z': [ythSecond2, ythFraction, ythAfterTimeSpace] => ythAfterTimeZ
|
||||
of ' ', '\t':
|
||||
[ythSecond2, ythFraction] => ythAfterTimeSpace
|
||||
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDaySpace
|
||||
[ythAfterTimeSpace, ythAfterDaySpace] => nil
|
||||
|
||||
proc guessType*(scalar: string): TypeHint {.raises: [].} =
|
||||
## Parse scalar string according to the RegEx table documented at
|
||||
@ -192,8 +267,10 @@ proc guessType*(scalar: string): TypeHint {.raises: [].} =
|
||||
of ythNULL: result = yTypeNull
|
||||
of ythTRUE, ythON, ythYES, ythY: result = yTypeBoolTrue
|
||||
of ythFALSE, ythOFF, ythNO, ythN: result = yTypeBoolFalse
|
||||
of ythInt, yth0: result = yTypeInteger
|
||||
of ythInt1, ythInt2, ythInt3, ythInt4, ythInt, yth0: result = yTypeInteger
|
||||
of ythDecimal, ythExponent: result = yTypeFloat
|
||||
of ythPointINF: result = yTypeFloatInf
|
||||
of ythPointNAN: result = yTypeFloatNaN
|
||||
of ythDay2, ythSecond2, ythFraction, ythAfterTimeZ, ythTzHour1, ythTzHour2,
|
||||
ythTzMinute1, ythTzMinute2: result = yTypeTimestamp
|
||||
else: result = yTypeUnknown
|
||||
|
@ -16,7 +16,7 @@
|
||||
## type. Please consult the serialization guide on the NimYAML website for more
|
||||
## information.
|
||||
|
||||
import tables, typetraits, strutils, macros, streams
|
||||
import tables, typetraits, strutils, macros, streams, times
|
||||
import parser, taglib, presenter, stream, ../private/internal, hints
|
||||
export stream
|
||||
# *something* in here needs externally visible `==`(x,y: AnchorId),
|
||||
@ -321,6 +321,72 @@ proc representObject*(value: char, ts: TagStyle, c: SerializationContext,
|
||||
## represents a char value as YAML scalar
|
||||
c.put(scalarEvent("" & value, tag, yAnchorNone))
|
||||
|
||||
proc yamlTag*(T: typedesc[Time]): TagId {.inline, raises: [].} = yTagTimestamp
|
||||
|
||||
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||
result: var Time)
|
||||
{.raises: [YamlConstructionError, YamlStreamError].} =
|
||||
constructScalarItem(s, item, Time):
|
||||
if guessType(item.scalarContent) == yTypeTimestamp:
|
||||
var
|
||||
tmp = newStringOfCap(60)
|
||||
pos = 8
|
||||
c: char
|
||||
while pos < item.scalarContent.len():
|
||||
c = item.scalarContent[pos]
|
||||
if c in {' ', '\t', 'T', 't'}: break
|
||||
inc(pos)
|
||||
if pos == item.scalarContent.len():
|
||||
tmp.add(item.scalarContent)
|
||||
tmp.add("T00:00:00+00:00")
|
||||
else:
|
||||
tmp.add(item.scalarContent[0 .. pos - 1])
|
||||
if c in {' ', '\t'}:
|
||||
while true:
|
||||
inc(pos)
|
||||
c = item.scalarContent[pos]
|
||||
if c notin {' ', '\t'}: break
|
||||
else: inc(pos)
|
||||
tmp.add("T")
|
||||
let timeStart = pos
|
||||
inc(pos, 7)
|
||||
var fractionStart = -1
|
||||
while pos < item.scalarContent.len():
|
||||
c = item.scalarContent[pos]
|
||||
if c in {'+', '-', 'Z', ' ', '\t'}: break
|
||||
elif c == '.': fractionStart = pos
|
||||
inc(pos)
|
||||
if fractionStart == -1:
|
||||
tmp.add(item.scalarContent[timeStart .. pos - 1])
|
||||
else:
|
||||
tmp.add(item.scalarContent[timeStart .. fractionStart - 1])
|
||||
if c in {'Z', ' ', '\t'}: tmp.add("+00:00")
|
||||
else:
|
||||
tmp.add(c)
|
||||
inc(pos)
|
||||
let tzStart = pos
|
||||
inc(pos)
|
||||
if pos < item.scalarContent.len() and item.scalarContent[pos] != ':':
|
||||
inc(pos)
|
||||
if pos - tzStart == 1: tmp.add('0')
|
||||
tmp.add(item.scalarContent[tzStart .. pos - 1])
|
||||
if pos == item.scalarContent.len(): tmp.add(":00")
|
||||
elif pos + 2 == item.scalarContent.len():
|
||||
tmp.add(":0")
|
||||
tmp.add(item.scalarContent[pos + 1])
|
||||
else:
|
||||
tmp.add(item.scalarContent[pos .. pos + 2])
|
||||
let info = tmp.parse("yyyy-M-d'T'H-mm-sszzz")
|
||||
result = info.toTime()
|
||||
else:
|
||||
raise s.constructionError("Not a parsable timestamp: " &
|
||||
escape(item.scalarContent))
|
||||
|
||||
proc representObject*(value: Time, ts: TagStyle, c: SerializationContext,
|
||||
tag: TagId) {.raises: [ValueError].} =
|
||||
let tmp = value.getGMTime()
|
||||
c.put(scalarEvent(tmp.format("yyyy-MM-dd'T'HH:mm:ss'Z'")))
|
||||
|
||||
proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} =
|
||||
let uri = nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')')
|
||||
result = lazyLoadTag(uri)
|
||||
@ -984,6 +1050,8 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||
raise s.constructionError("not implemented!")
|
||||
of yTypeUnknown:
|
||||
possibleTagIds.add(yamlTag(string))
|
||||
of yTypeTimestamp:
|
||||
possibleTagIds.add(yamlTag(Time))
|
||||
of yTagExclamationMark:
|
||||
possibleTagIds.add(yamlTag(string))
|
||||
else:
|
||||
|
Loading…
x
Reference in New Issue
Block a user