mirror of
https://github.com/status-im/NimYAML.git
synced 2025-01-12 20:44:46 +00:00
Implemented !!timestamp
This commit is contained in:
parent
05c4aa733c
commit
64f68ae1af
@ -5,7 +5,7 @@
|
|||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
||||||
import "../yaml"
|
import "../yaml"
|
||||||
import unittest, strutils, streams, tables
|
import unittest, strutils, streams, tables, times
|
||||||
|
|
||||||
type
|
type
|
||||||
MyTuple = tuple
|
MyTuple = tuple
|
||||||
@ -208,6 +208,14 @@ suite "Serialization":
|
|||||||
var output = dump(input, tsNone, asTidy, blockOnly)
|
var output = dump(input, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual yamlDirs & "\n!n!nil:string \"\"", output
|
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":
|
test "Load string sequence":
|
||||||
let input = newStringStream(" - a\n - b")
|
let input = newStringStream(" - a\n - b")
|
||||||
var result: seq[string]
|
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``
|
## ``yTypeBoolTrue`` ``y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON``
|
||||||
## ``yTypeBoolFalse`` ``n|N|no|No|NO|false|False|FALSE|off|Off|OFF``
|
## ``yTypeBoolFalse`` ``n|N|no|No|NO|false|False|FALSE|off|Off|OFF``
|
||||||
## ``yTypeNull`` ``~ | null | Null | NULL``
|
## ``yTypeNull`` ``~ | null | Null | NULL``
|
||||||
|
## ``yTypeTimestamp`` see `here <http://yaml.org/type/timestamp.html>`_.
|
||||||
## ``yTypeUnknown`` ``*``
|
## ``yTypeUnknown`` ``*``
|
||||||
## ================== =========================
|
## ================== =========================
|
||||||
yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue,
|
yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue,
|
||||||
yTypeBoolFalse, yTypeNull, yTypeUnknown
|
yTypeBoolFalse, yTypeNull, yTypeUnknown, yTypeTimestamp
|
||||||
|
|
||||||
YamlTypeHintState = enum
|
YamlTypeHintState = enum
|
||||||
ythInitial,
|
ythInitial,
|
||||||
@ -59,7 +60,16 @@ type
|
|||||||
|
|
||||||
ythPointLowerIN, ythPointLowerN, ythPointLowerNA,
|
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 =
|
macro typeHintStateMachine(c: untyped, content: untyped): typed =
|
||||||
yAssert content.kind == nnkStmtList
|
yAssert content.kind == nnkStmtList
|
||||||
@ -101,20 +111,78 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
|||||||
typeHintStateMachine ch:
|
typeHintStateMachine ch:
|
||||||
of '~': ythInitial => ythNULL
|
of '~': ythInitial => ythNULL
|
||||||
of '.':
|
of '.':
|
||||||
[yth0, ythInt] => ythDecimal
|
[yth0, ythInt1, ythInt2, ythInt3, ythInt4, ythInt] => ythDecimal
|
||||||
[ythInitial, ythMinus] => ythPoint
|
[ythInitial, ythMinus] => ythPoint
|
||||||
of '+': ythNumE => ythNumEPlusMinus
|
ythSecond2 => ythFraction
|
||||||
|
of '+':
|
||||||
|
ythNumE => ythNumEPlusMinus
|
||||||
|
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
||||||
of '-':
|
of '-':
|
||||||
ythInitial => ythMinus
|
ythInitial => ythMinus
|
||||||
ythNumE => ythNumEPlusMinus
|
ythNumE => ythNumEPlusMinus
|
||||||
|
[ythInt4, ythInt4Zero] => ythYearMinus
|
||||||
|
ythMonth1 => ythMonthMinusNoYmd
|
||||||
|
ythMonth2 => ythMonthMinus
|
||||||
|
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
||||||
|
of ':':
|
||||||
|
[ythHour1, ythHour2] => ythHourColon
|
||||||
|
ythMinute2 => ythMinuteColon
|
||||||
|
[ythTzHour1, ythTzHour2] => ythTzHourColon
|
||||||
of '0':
|
of '0':
|
||||||
[ythInitial, ythMinus] => yth0
|
ythInitial => ythInt1Zero
|
||||||
|
ythMinus => yth0
|
||||||
[ythNumE, ythNumEPlusMinus] => ythExponent
|
[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':
|
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
|
[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':
|
of 'a':
|
||||||
ythF => ythLowerFA
|
ythF => ythLowerFA
|
||||||
ythPointN => ythPointNA
|
ythPointN => ythPointNA
|
||||||
@ -174,7 +242,9 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
|||||||
of 'S':
|
of 'S':
|
||||||
ythFAL => ythFALS
|
ythFAL => ythFALS
|
||||||
ythYE => ythYES
|
ythYE => ythYES
|
||||||
of 't', 'T': ythInitial => ythT
|
of 't', 'T':
|
||||||
|
ythInitial => ythT
|
||||||
|
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT
|
||||||
of 'u':
|
of 'u':
|
||||||
ythN => ythLowerNU
|
ythN => ythLowerNU
|
||||||
ythLowerTR => ythLowerTRU
|
ythLowerTR => ythLowerTRU
|
||||||
@ -182,6 +252,11 @@ template advanceTypeHint(ch: char) {.dirty.} =
|
|||||||
ythN => ythNU
|
ythN => ythNU
|
||||||
ythTR => ythTRU
|
ythTR => ythTRU
|
||||||
of 'y', 'Y': ythInitial => ythY
|
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: [].} =
|
proc guessType*(scalar: string): TypeHint {.raises: [].} =
|
||||||
## Parse scalar string according to the RegEx table documented at
|
## 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 ythNULL: result = yTypeNull
|
||||||
of ythTRUE, ythON, ythYES, ythY: result = yTypeBoolTrue
|
of ythTRUE, ythON, ythYES, ythY: result = yTypeBoolTrue
|
||||||
of ythFALSE, ythOFF, ythNO, ythN: result = yTypeBoolFalse
|
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 ythDecimal, ythExponent: result = yTypeFloat
|
||||||
of ythPointINF: result = yTypeFloatInf
|
of ythPointINF: result = yTypeFloatInf
|
||||||
of ythPointNAN: result = yTypeFloatNaN
|
of ythPointNAN: result = yTypeFloatNaN
|
||||||
|
of ythDay2, ythSecond2, ythFraction, ythAfterTimeZ, ythTzHour1, ythTzHour2,
|
||||||
|
ythTzMinute1, ythTzMinute2: result = yTypeTimestamp
|
||||||
else: result = yTypeUnknown
|
else: result = yTypeUnknown
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
## type. Please consult the serialization guide on the NimYAML website for more
|
## type. Please consult the serialization guide on the NimYAML website for more
|
||||||
## information.
|
## information.
|
||||||
|
|
||||||
import tables, typetraits, strutils, macros, streams
|
import tables, typetraits, strutils, macros, streams, times
|
||||||
import parser, taglib, presenter, stream, ../private/internal, hints
|
import parser, taglib, presenter, stream, ../private/internal, hints
|
||||||
export stream
|
export stream
|
||||||
# *something* in here needs externally visible `==`(x,y: AnchorId),
|
# *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
|
## represents a char value as YAML scalar
|
||||||
c.put(scalarEvent("" & value, tag, yAnchorNone))
|
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: [].} =
|
proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} =
|
||||||
let uri = nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')')
|
let uri = nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')')
|
||||||
result = lazyLoadTag(uri)
|
result = lazyLoadTag(uri)
|
||||||
@ -984,6 +1050,8 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
|||||||
raise s.constructionError("not implemented!")
|
raise s.constructionError("not implemented!")
|
||||||
of yTypeUnknown:
|
of yTypeUnknown:
|
||||||
possibleTagIds.add(yamlTag(string))
|
possibleTagIds.add(yamlTag(string))
|
||||||
|
of yTypeTimestamp:
|
||||||
|
possibleTagIds.add(yamlTag(Time))
|
||||||
of yTagExclamationMark:
|
of yTagExclamationMark:
|
||||||
possibleTagIds.add(yamlTag(string))
|
possibleTagIds.add(yamlTag(string))
|
||||||
else:
|
else:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user