2016-01-24 10:44:10 +00:00
|
|
|
# NimYAML - YAML implementation in Nim
|
2023-08-29 21:23:15 +00:00
|
|
|
# (c) Copyright 2015-2023 Felix Krause
|
2016-01-24 10:44:10 +00:00
|
|
|
#
|
|
|
|
# See the file "copying.txt", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
|
2016-09-21 19:20:57 +00:00
|
|
|
## =================
|
2021-05-17 22:31:47 +00:00
|
|
|
## Module yaml/hints
|
2016-09-21 19:20:57 +00:00
|
|
|
## =================
|
|
|
|
##
|
|
|
|
## The hints API enables you to guess the type of YAML scalars.
|
|
|
|
|
2016-09-20 19:53:38 +00:00
|
|
|
import macros
|
2017-02-06 19:39:04 +00:00
|
|
|
import private/internal
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-01-14 18:58:38 +00:00
|
|
|
type
|
2016-09-20 19:53:38 +00:00
|
|
|
TypeHint* = enum
|
|
|
|
## A type hint can be computed from scalar content and tells you what
|
|
|
|
## NimYAML thinks the scalar's type is. It is generated by
|
|
|
|
## `guessType <#guessType,string>`_ The first matching RegEx
|
|
|
|
## in the following table will be the type hint of a scalar string.
|
|
|
|
##
|
|
|
|
## You can use it to determine the type of YAML scalars that have a '?'
|
|
|
|
## non-specific tag, but using this feature is completely optional.
|
|
|
|
##
|
2023-04-10 15:17:03 +00:00
|
|
|
## See also: https://yaml.org/spec/1.2.2/#103-core-schema
|
|
|
|
##
|
2016-09-20 19:53:38 +00:00
|
|
|
## ================== =========================
|
|
|
|
## Name RegEx
|
|
|
|
## ================== =========================
|
2023-04-10 15:17:03 +00:00
|
|
|
## ``yTypeInteger`` ``[-+]? [0-9]+``
|
|
|
|
## ``yTypeFloat`` ``[-+]? ( \. [0-9]+ | [0-9]+ ( \. [0-9]* )? ) ( [eE] [-+]? [0-9]+ )?``
|
|
|
|
## ``yTypeFloatInf`` ``[-+]? ( \.inf | \.Inf | \.INF )``
|
|
|
|
## ``yTypeFloatNaN`` ``\.nan | \.NaN | \.NAN``
|
|
|
|
## ``yTypeBoolTrue`` ``true | True | TRUE``
|
|
|
|
## ``yTypeBoolFalse`` ``false | False | FALSE``
|
|
|
|
## ``yTypeNull`` ``null | Null | NULL | ~``
|
2016-11-08 20:13:01 +00:00
|
|
|
## ``yTypeTimestamp`` see `here <http://yaml.org/type/timestamp.html>`_.
|
2016-09-20 19:53:38 +00:00
|
|
|
## ``yTypeUnknown`` ``*``
|
|
|
|
## ================== =========================
|
|
|
|
yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue,
|
2016-11-08 20:13:01 +00:00
|
|
|
yTypeBoolFalse, yTypeNull, yTypeUnknown, yTypeTimestamp
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-02 15:48:22 +00:00
|
|
|
YamlTypeHintState = enum
|
|
|
|
ythInitial,
|
|
|
|
ythF, ythFA, ythFAL, ythFALS, ythFALSE,
|
|
|
|
ythN, ythNU, ythNUL, ythNULL,
|
|
|
|
ythT, ythTR, ythTRU, ythTRUE,
|
2016-07-07 15:14:18 +00:00
|
|
|
|
2016-04-02 15:48:22 +00:00
|
|
|
ythPoint, ythPointI, ythPointIN, ythPointINF,
|
|
|
|
ythPointN, ythPointNA, ythPointNAN,
|
2016-07-07 15:14:18 +00:00
|
|
|
|
2023-04-10 15:17:03 +00:00
|
|
|
ythLowerF, ythLowerFA, ythLowerFAL, ythLowerFALS,
|
|
|
|
ythLowerN, ythLowerNU, ythLowerNUL,
|
|
|
|
ythLowerT, ythLowerTR, ythLowerTRU,
|
2016-07-07 15:14:18 +00:00
|
|
|
|
2023-04-10 15:17:03 +00:00
|
|
|
ythPointLowerI, ythPointLowerIN,
|
|
|
|
ythPointLowerN, ythPointLowerNA,
|
2016-07-07 15:14:18 +00:00
|
|
|
|
2023-04-10 15:17:03 +00:00
|
|
|
ythMinus, ythPlus, ythInt1, ythInt2, ythInt3, ythInt4, ythInt,
|
2016-11-08 20:13:01 +00:00
|
|
|
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
|
2016-01-14 18:58:38 +00:00
|
|
|
|
2020-03-08 18:22:34 +00:00
|
|
|
macro typeHintStateMachine(c: untyped, content: varargs[untyped]) =
|
2017-06-30 13:07:43 +00:00
|
|
|
yAssert content.kind == nnkArgList
|
2016-04-02 15:48:22 +00:00
|
|
|
result = newNimNode(nnkCaseStmt, content).add(copyNimNode(c))
|
2017-07-10 17:52:34 +00:00
|
|
|
for branch in content.children:
|
2016-08-09 18:47:22 +00:00
|
|
|
yAssert branch.kind == nnkOfBranch
|
2016-07-07 15:14:18 +00:00
|
|
|
var
|
2016-04-02 15:48:22 +00:00
|
|
|
charBranch = newNimNode(nnkOfBranch, branch)
|
|
|
|
i = 0
|
|
|
|
stateBranches = newNimNode(nnkCaseStmt, branch).add(
|
|
|
|
newIdentNode("typeHintState"))
|
|
|
|
while branch[i].kind != nnkStmtList:
|
|
|
|
charBranch.add(copyNimTree(branch[i]))
|
|
|
|
inc(i)
|
|
|
|
for rule in branch[i].children:
|
2016-08-09 18:47:22 +00:00
|
|
|
yAssert rule.kind == nnkInfix
|
2020-03-08 18:22:34 +00:00
|
|
|
yAssert rule[0].strVal == "=>"
|
2016-04-02 15:48:22 +00:00
|
|
|
var stateBranch = newNimNode(nnkOfBranch, rule)
|
|
|
|
case rule[1].kind
|
|
|
|
of nnkBracket:
|
|
|
|
for item in rule[1].children: stateBranch.add(item)
|
|
|
|
of nnkIdent: stateBranch.add(rule[1])
|
2016-08-09 18:47:22 +00:00
|
|
|
else: internalError("Invalid rule kind: " & $rule[1].kind)
|
2016-04-02 15:48:22 +00:00
|
|
|
if rule[2].kind == nnkNilLit:
|
|
|
|
stateBranch.add(newStmtList(newNimNode(nnkDiscardStmt).add(
|
2016-01-14 18:58:38 +00:00
|
|
|
newEmptyNode())))
|
2016-04-02 15:48:22 +00:00
|
|
|
else:
|
|
|
|
stateBranch.add(newStmtList(newAssignment(
|
2016-01-14 18:58:38 +00:00
|
|
|
newIdentNode("typeHintState"), copyNimTree(rule[2]))))
|
2016-04-02 15:48:22 +00:00
|
|
|
stateBranches.add(stateBranch)
|
|
|
|
stateBranches.add(newNimNode(nnkElse).add(newStmtList(
|
|
|
|
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown")))))
|
|
|
|
charBranch.add(newStmtList(stateBranches))
|
|
|
|
result.add(charBranch)
|
|
|
|
result.add(newNimNode(nnkElse).add(newStmtList(
|
|
|
|
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown")))))
|
2016-01-14 18:58:38 +00:00
|
|
|
|
|
|
|
template advanceTypeHint(ch: char) {.dirty.} =
|
2016-04-02 15:48:22 +00:00
|
|
|
typeHintStateMachine ch:
|
|
|
|
of '~': ythInitial => ythNULL
|
|
|
|
of '.':
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythInt1, ythInt2, ythInt3, ythInt4, ythInt] => ythDecimal
|
|
|
|
[ythInitial, ythMinus, ythPlus] => ythPoint
|
|
|
|
ythSecond2 => ythFraction
|
2016-11-08 20:13:01 +00:00
|
|
|
of '+':
|
2023-04-10 15:17:03 +00:00
|
|
|
ythInitial => ythPlus
|
|
|
|
ythNumE => ythNumEPlusMinus
|
2016-11-08 20:13:01 +00:00
|
|
|
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
2016-04-02 15:48:22 +00:00
|
|
|
of '-':
|
2016-11-08 20:13:01 +00:00
|
|
|
ythInitial => ythMinus
|
|
|
|
ythNumE => ythNumEPlusMinus
|
2023-04-10 15:17:03 +00:00
|
|
|
ythInt4 => ythYearMinus
|
2016-11-08 20:13:01 +00:00
|
|
|
ythMonth1 => ythMonthMinusNoYmd
|
|
|
|
ythMonth2 => ythMonthMinus
|
|
|
|
[ythFraction, ythSecond2] => ythAfterTimePlusMinus
|
2016-11-10 09:12:32 +00:00
|
|
|
of '_':
|
|
|
|
[ythInt1, ythInt2, ythInt3, ythInt4] => ythInt
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythInt, ythDecimal] => nil
|
2016-11-08 20:13:01 +00:00
|
|
|
of ':':
|
|
|
|
[ythHour1, ythHour2] => ythHourColon
|
|
|
|
ythMinute2 => ythMinuteColon
|
|
|
|
[ythTzHour1, ythTzHour2] => ythTzHourColon
|
2023-04-10 15:17:03 +00:00
|
|
|
of '0'..'9':
|
2016-11-08 20:13:01 +00:00
|
|
|
ythInitial => ythInt1
|
|
|
|
ythInt1 => ythInt2
|
|
|
|
ythInt2 => ythInt3
|
|
|
|
ythInt3 => ythInt4
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythInt4, ythMinus, ythPlus] => ythInt
|
2016-04-02 15:48:22 +00:00
|
|
|
[ythNumE, ythNumEPlusMinus] => ythExponent
|
2016-11-08 20:13:01 +00:00
|
|
|
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
|
2023-04-10 15:17:03 +00:00
|
|
|
ythPoint => ythDecimal
|
2016-11-08 20:13:01 +00:00
|
|
|
[ythInt, ythDecimal, ythExponent, ythFraction] => nil
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'a':
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythF, ythLowerF] => ythLowerFA
|
|
|
|
ythPointN => ythPointNA
|
|
|
|
ythPointLowerN => ythPointLowerNA
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'A':
|
|
|
|
ythF => ythFA
|
|
|
|
ythPointN => ythPointNA
|
|
|
|
of 'e':
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythInt, ythDecimal,
|
|
|
|
ythInt1, ythInt2, ythInt3, ythInt4] => ythNumE
|
2016-04-02 15:48:22 +00:00
|
|
|
ythLowerFALS => ythFALSE
|
|
|
|
ythLowerTRU => ythTRUE
|
|
|
|
of 'E':
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythInt, ythDecimal,
|
|
|
|
ythInt1, ythInt2, ythInt3, ythInt4] => ythNumE
|
2016-04-02 15:48:22 +00:00
|
|
|
ythFALS => ythFALSE
|
|
|
|
ythTRU => ythTRUE
|
|
|
|
of 'f':
|
2023-04-10 15:17:03 +00:00
|
|
|
ythInitial => ythLowerF
|
2016-04-02 15:48:22 +00:00
|
|
|
ythPointLowerIN => ythPointINF
|
|
|
|
of 'F':
|
|
|
|
ythInitial => ythF
|
|
|
|
ythPointIN => ythPointINF
|
2023-04-10 15:17:03 +00:00
|
|
|
of 'i': ythPoint => ythPointLowerI
|
|
|
|
of 'I': ythPoint => ythPointI
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'l':
|
|
|
|
ythLowerNU => ythLowerNUL
|
|
|
|
ythLowerNUL => ythNULL
|
|
|
|
ythLowerFA => ythLowerFAL
|
|
|
|
of 'L':
|
|
|
|
ythNU => ythNUL
|
|
|
|
ythNUL => ythNULL
|
|
|
|
ythFA => ythFAL
|
|
|
|
of 'n':
|
2023-04-10 15:17:03 +00:00
|
|
|
ythInitial => ythLowerN
|
2016-04-02 15:48:22 +00:00
|
|
|
ythPoint => ythPointLowerN
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythPointI, ythPointLowerI] => ythPointLowerIN
|
2016-04-02 15:48:22 +00:00
|
|
|
ythPointLowerNA => ythPointNAN
|
|
|
|
of 'N':
|
|
|
|
ythInitial => ythN
|
|
|
|
ythPoint => ythPointN
|
|
|
|
ythPointI => ythPointIN
|
|
|
|
ythPointNA => ythPointNAN
|
2023-04-10 15:17:03 +00:00
|
|
|
of 'r': [ythT, ythLowerT] => ythLowerTR
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'R': ythT => ythTR
|
|
|
|
of 's':
|
|
|
|
ythLowerFAL => ythLowerFALS
|
|
|
|
of 'S':
|
|
|
|
ythFAL => ythFALS
|
2023-04-10 15:17:03 +00:00
|
|
|
of 't':
|
|
|
|
ythInitial => ythLowerT
|
|
|
|
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT
|
|
|
|
of 'T':
|
2016-11-08 20:13:01 +00:00
|
|
|
ythInitial => ythT
|
|
|
|
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'u':
|
2023-04-10 15:17:03 +00:00
|
|
|
[ythN, ythLowerN] => ythLowerNU
|
|
|
|
ythLowerTR => ythLowerTRU
|
2016-04-02 15:48:22 +00:00
|
|
|
of 'U':
|
|
|
|
ythN => ythNU
|
|
|
|
ythTR => ythTRU
|
2016-11-08 20:13:01 +00:00
|
|
|
of 'Z': [ythSecond2, ythFraction, ythAfterTimeSpace] => ythAfterTimeZ
|
|
|
|
of ' ', '\t':
|
|
|
|
[ythSecond2, ythFraction] => ythAfterTimeSpace
|
|
|
|
[ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDaySpace
|
|
|
|
[ythAfterTimeSpace, ythAfterDaySpace] => nil
|
2016-01-14 18:58:38 +00:00
|
|
|
|
2016-09-20 19:53:38 +00:00
|
|
|
proc guessType*(scalar: string): TypeHint {.raises: [].} =
|
|
|
|
## Parse scalar string according to the RegEx table documented at
|
|
|
|
## `TypeHint <#TypeHind>`_.
|
2016-04-02 15:48:22 +00:00
|
|
|
var typeHintState: YamlTypeHintState = ythInitial
|
|
|
|
for c in scalar: advanceTypeHint(c)
|
|
|
|
case typeHintState
|
2017-01-12 10:19:46 +00:00
|
|
|
of ythNULL, ythInitial: result = yTypeNull
|
2023-04-10 15:17:03 +00:00
|
|
|
of ythTRUE: result = yTypeBoolTrue
|
|
|
|
of ythFALSE: result = yTypeBoolFalse
|
|
|
|
of ythInt1, ythInt2, ythInt3, ythInt4, ythInt: result = yTypeInteger
|
2016-04-02 15:48:22 +00:00
|
|
|
of ythDecimal, ythExponent: result = yTypeFloat
|
|
|
|
of ythPointINF: result = yTypeFloatInf
|
|
|
|
of ythPointNAN: result = yTypeFloatNaN
|
2016-11-08 20:13:01 +00:00
|
|
|
of ythDay2, ythSecond2, ythFraction, ythAfterTimeZ, ythTzHour1, ythTzHour2,
|
|
|
|
ythTzMinute1, ythTzMinute2: result = yTypeTimestamp
|
2016-08-30 20:15:29 +00:00
|
|
|
else: result = yTypeUnknown
|