mirror of https://github.com/status-im/NimYAML.git
Various improvements
* Better JSON serialization (map bool literals to true/false if possible) * Fixed a problem where the tag of block sequence would be wrongly placed * Always output "" when dumping empty strings * Added helper functions to create YamlStreamEvents. * Moved procs for YamlStreamEvents to private/events.nim * renamed dump() to present() * Added dump() and load() to yaml.serialization
This commit is contained in:
parent
9ff93efb11
commit
a094089fb9
|
@ -13,8 +13,9 @@ type
|
|||
dFlowSequenceStart
|
||||
|
||||
proc needsEscaping(scalar: string): bool =
|
||||
scalar.find({'{', '}', '[', ']', ',', '#', '-', ':', '?', '%', '\x0A',
|
||||
'\c'}) != -1
|
||||
scalar.len == 0 or
|
||||
scalar.find({'{', '}', '[', ']', ',', '#', '-', ':', '?', '%',
|
||||
'\x0A', '\c'}) != -1
|
||||
|
||||
proc writeDoubleQuoted(scalar: string, s: Stream) =
|
||||
s.write('"')
|
||||
|
@ -116,8 +117,8 @@ proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: YamlTagLibrary,
|
|||
target.write(cast[byte]('a') + cast[byte](anchor))
|
||||
target.write(' ')
|
||||
|
||||
proc dump*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
||||
style: YamlDumpStyle = yDumpDefault, indentationStep: int = 2) =
|
||||
proc present*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
||||
style: YamlDumpStyle = yDumpDefault, indentationStep: int = 2) =
|
||||
var
|
||||
cached = initQueue[YamlStreamEvent]()
|
||||
cacheIterator = iterator(): YamlStreamEvent =
|
||||
|
@ -147,8 +148,20 @@ proc dump*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
|||
writeTagAndAnchor(target,
|
||||
item.scalarTag, tagLib, item.scalarAnchor)
|
||||
|
||||
if item.scalarContent.needsEscaping or
|
||||
style in [yDumpCanonical, yDumpJson]:
|
||||
if (style == yDumpJson and item.scalarTag in [yTagQuestionMark,
|
||||
yTagBoolean] and
|
||||
item.scalarType in [yTypeBoolTrue, yTypeBoolFalse]):
|
||||
if item.scalarType == yTypeBoolTrue:
|
||||
target.write("true")
|
||||
else:
|
||||
target.write("false")
|
||||
elif style == yDumpCanonical or item.scalarContent.needsEscaping or
|
||||
(style == yDumpJson and
|
||||
(item.scalarTag notin [yTagQuestionMark, yTagInteger, yTagFloat,
|
||||
yTagBoolean, yTagNull] or
|
||||
(item.scalarTag == yTagQuestionMark and item.scalarType notin
|
||||
[yTypeBoolFalse, yTypeBoolTrue, yTypeInteger, yTypeFloat,
|
||||
yTypeNull]))):
|
||||
writeDoubleQuoted(item.scalarContent, target)
|
||||
else:
|
||||
target.write(item.scalarContent)
|
||||
|
@ -193,21 +206,15 @@ proc dump*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
|||
item.seqTag, tagLib, item.seqAnchor)
|
||||
else:
|
||||
if style != yDumpJson:
|
||||
target.write('\x0A')
|
||||
writeTagAndAnchor(target,
|
||||
item.seqTag, tagLib, item.seqAnchor)
|
||||
target.write('\x0A')
|
||||
indentation += indentationStep
|
||||
else:
|
||||
if nextState == dBlockSequenceItem:
|
||||
if style != yDumpJson:
|
||||
writeTagAndAnchor(target,
|
||||
item.seqTag, tagLib, item.seqAnchor)
|
||||
startItem(target, style, indentation, levels[levels.high])
|
||||
else:
|
||||
startItem(target, style, indentation, levels[levels.high])
|
||||
if style != yDumpJson:
|
||||
writeTagAndAnchor(target,
|
||||
item.seqTag, tagLib, item.seqAnchor)
|
||||
startItem(target, style, indentation, levels[levels.high])
|
||||
if style != yDumpJson:
|
||||
writeTagAndAnchor(target,
|
||||
item.seqTag, tagLib, item.seqAnchor)
|
||||
indentation += indentationStep
|
||||
|
||||
if nextState == dFlowSequenceStart:
|
||||
|
@ -267,7 +274,8 @@ proc dump*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
|||
indentation += indentationStep
|
||||
else:
|
||||
if nextState in
|
||||
[dBlockExplicitMapValue, dBlockImplicitMapValue]:
|
||||
[dBlockExplicitMapValue, dBlockImplicitMapValue,
|
||||
dBlockImplicitMapKey]:
|
||||
if style != yDumpJson:
|
||||
writeTagAndAnchor(target,
|
||||
item.mapTag, tagLib, item.mapAnchor)
|
||||
|
@ -368,5 +376,5 @@ proc transform*(input: Stream, output: Stream, style: YamlDumpStyle,
|
|||
var
|
||||
tagLib = extendedTagLibrary()
|
||||
parser = newParser(tagLib)
|
||||
dump(parser.parse(input), output, tagLib, style,
|
||||
indentationStep)
|
||||
present(parser.parse(input), output, tagLib, style,
|
||||
indentationStep)
|
|
@ -29,6 +29,28 @@ type
|
|||
BlockScalarStyle = enum
|
||||
bsLiteral, bsFolded
|
||||
|
||||
proc `$`*(id: TagId): string =
|
||||
case id
|
||||
of yTagQuestionMark: "?"
|
||||
of yTagExclamationMark: "!"
|
||||
of yTagString: "!!str"
|
||||
of yTagSequence: "!!seq"
|
||||
of yTagMap: "!!map"
|
||||
of yTagNull: "!!null"
|
||||
of yTagBoolean: "!!bool"
|
||||
of yTagInteger: "!!int"
|
||||
of yTagFloat: "!!float"
|
||||
of yTagOrderedMap: "!!omap"
|
||||
of yTagPairs: "!!pairs"
|
||||
of yTagSet: "!!set"
|
||||
of yTagBinary: "!!binary"
|
||||
of yTagMerge: "!!merge"
|
||||
of yTagTimestamp: "!!timestamp"
|
||||
of yTagValue: "!!value"
|
||||
of yTagYaml: "!!yaml"
|
||||
else:
|
||||
"<" & $cast[int](id) & ">"
|
||||
|
||||
proc newParser*(tagLib: YamlTagLibrary): YamlSequentialParser =
|
||||
new(result)
|
||||
result.tagLib = tagLib
|
||||
|
@ -40,55 +62,6 @@ proc anchor*(parser: YamlSequentialParser, id: AnchorId): string =
|
|||
return pair[0]
|
||||
return nil
|
||||
|
||||
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool =
|
||||
if left.kind != right.kind:
|
||||
return false
|
||||
case left.kind
|
||||
of yamlStartDocument, yamlEndDocument, yamlEndMap, yamlEndSequence:
|
||||
result = true
|
||||
of yamlStartMap:
|
||||
result = left.mapAnchor == right.mapAnchor and
|
||||
left.mapTag == right.mapTag
|
||||
of yamlStartSequence:
|
||||
result = left.seqAnchor == right.seqAnchor and
|
||||
left.seqTag == right.seqTag
|
||||
of yamlScalar:
|
||||
result = left.scalarAnchor == right.scalarAnchor and
|
||||
left.scalarTag == right.scalarTag and
|
||||
left.scalarContent == right.scalarContent and
|
||||
left.scalarType == right.scalarType
|
||||
of yamlAlias:
|
||||
result = left.aliasTarget == right.aliasTarget
|
||||
of yamlError, yamlWarning:
|
||||
result = left.description == right.description and
|
||||
left.line == right.line and left.column == right.column
|
||||
|
||||
proc `$`*(event: YamlStreamEvent): string =
|
||||
result = $event.kind & '('
|
||||
case event.kind
|
||||
of yamlEndMap, yamlEndSequence, yamlStartDocument, yamlEndDocument:
|
||||
discard
|
||||
of yamlStartMap:
|
||||
result &= "tag=" & $event.mapTag
|
||||
if event.mapAnchor != yAnchorNone:
|
||||
result &= ", anchor=" & $event.mapAnchor
|
||||
of yamlStartSequence:
|
||||
result &= "tag=" & $event.seqTag
|
||||
if event.seqAnchor != yAnchorNone:
|
||||
result &= ", anchor=" & $event.seqAnchor
|
||||
of yamlScalar:
|
||||
result &= "tag=" & $event.scalarTag
|
||||
if event.scalarAnchor != yAnchorNone:
|
||||
result &= ", anchor=" & $event.scalarAnchor
|
||||
result &= ", typeHint=" & $event.scalarType
|
||||
result &= ", content=\"" & event.scalarContent & '\"'
|
||||
of yamlAlias:
|
||||
result &= "aliasTarget=" & $event.aliasTarget
|
||||
of yamlWarning, yamlError:
|
||||
result &= "line=" & $event.line & ", column=" & $event.column
|
||||
result &= ", description=\"" & event.description & '\"'
|
||||
result &= ")"
|
||||
|
||||
template yieldWarning(d: string) {.dirty.} =
|
||||
yield YamlStreamEvent(kind: yamlWarning, description: d,
|
||||
line: lex.line, column: lex.column)
|
||||
|
|
|
@ -26,8 +26,7 @@ suite "Serialization":
|
|||
test "Serialize string sequence":
|
||||
var input = @["a", "b"]
|
||||
var output = newStringStream()
|
||||
dump(wrapWithDocument(serialize(input)), output, coreTagLibrary(),
|
||||
yDumpBlockOnly)
|
||||
dump(input, output, yDumpBlockOnly)
|
||||
assert output.data == "%YAML 1.2\n--- \n- a\n- b"
|
||||
|
||||
test "Load Table[int, string]":
|
||||
|
@ -47,8 +46,7 @@ suite "Serialization":
|
|||
input[23] = "dreiundzwanzig"
|
||||
input[42] = "zweiundvierzig"
|
||||
var output = newStringStream()
|
||||
dump(wrapWithDocument(serialize(input)), output, coreTagLibrary(),
|
||||
yDumpBlockOnly)
|
||||
dump(input, output, yDumpBlockOnly)
|
||||
assert output.data == "%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig"
|
||||
|
||||
test "Load Sequences in Sequence":
|
||||
|
@ -67,8 +65,7 @@ suite "Serialization":
|
|||
test "Serialize Sequences in Sequence":
|
||||
let input = @[@[1, 2, 3], @[4, 5], @[6]]
|
||||
var output = newStringStream()
|
||||
dump(wrapWithDocument(serialize(input)), output, coreTagLibrary(),
|
||||
yDumpDefault)
|
||||
dump(input, output, yDumpDefault)
|
||||
assert output.data == "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]"
|
||||
|
||||
test "Load custom object":
|
||||
|
@ -86,6 +83,5 @@ suite "Serialization":
|
|||
test "Serialize custom object":
|
||||
let input = Person(firstname: "Peter", surname: "Pan", age: 12)
|
||||
var output = newStringStream()
|
||||
dump(wrapWithDocument(serialize(input)), output, coreTagLibrary(),
|
||||
yDumpBlockOnly)
|
||||
dump(input, output, yDumpBlockOnly)
|
||||
assert output.data == "%YAML 1.2\n--- \nfirstname: Peter\nsurname: Pan\nage: 12"
|
23
yaml.nim
23
yaml.nim
|
@ -85,7 +85,7 @@ type
|
|||
## The value ``mapMayHaveKeyObjects`` is a hint from a serializer and is
|
||||
## used for choosing an appropriate presentation mode for a YAML map
|
||||
## (flow or block, explicit or implicit) by
|
||||
## `dump <#dump,YamlStream,Stream,YamlTagLibrary,YamlDumpStyle,int>`_.
|
||||
## `present <#present,YamlStream,Stream,YamlTagLibrary,YamlDumpStyle,int>`_.
|
||||
## If it is set to ``false``, the map may only have scalars as keys.
|
||||
##
|
||||
## The value ``scalarType`` is a hint from the lexer, see
|
||||
|
@ -239,8 +239,22 @@ proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool
|
|||
proc `$`*(event: YamlStreamEvent): string
|
||||
## outputs a human-readable string describing the given event
|
||||
|
||||
proc startDocEvent*(): YamlStreamEvent {.inline.}
|
||||
proc endDocEvent*(): YamlStreamEvent {.inline.}
|
||||
proc startMapEvent*(tag: TagId = yTagQuestionMark,
|
||||
anchor: AnchorId = yAnchorNone,
|
||||
mayHaveKeyObjects: bool = true): YamlStreamEvent {.inline.}
|
||||
proc endMapEvent*(): YamlStreamEvent {.inline.}
|
||||
proc startSeqEvent*(tag: TagId = yTagQuestionMark,
|
||||
anchor: AnchorId = yAnchorNone): YamlStreamEvent {.inline.}
|
||||
proc endSeqEvent*(): YamlStreamEvent {.inline.}
|
||||
proc scalarEvent*(content: string = "", tag: TagId = yTagQuestionMark,
|
||||
anchor: AnchorId = yAnchorNone,
|
||||
typeHint: YamlTypeHint = yTypeUnknown):
|
||||
YamlStreamEvent {.inline.}
|
||||
|
||||
proc `==`*(left, right: TagId): bool {.borrow.}
|
||||
proc `$`*(id: TagId): string {.borrow.}
|
||||
proc `$`*(id: TagId): string
|
||||
proc hash*(id: TagId): Hash {.borrow.}
|
||||
|
||||
proc `==`*(left, right: AnchorId): bool {.borrow.}
|
||||
|
@ -310,8 +324,8 @@ proc constructJson*(s: YamlStream): seq[JsonNode]
|
|||
## check for these values and will output invalid JSON when rendering one
|
||||
## of these values into a JSON character stream.
|
||||
|
||||
proc dump*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
||||
style: YamlDumpStyle = yDumpDefault, indentationStep: int = 2)
|
||||
proc present*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
||||
style: YamlDumpStyle = yDumpDefault, indentationStep: int = 2)
|
||||
## Convert ``s`` to a YAML character stream and write it to ``target``.
|
||||
|
||||
proc transform*(input: Stream, output: Stream, style: YamlDumpStyle,
|
||||
|
@ -323,6 +337,7 @@ proc transform*(input: Stream, output: Stream, style: YamlDumpStyle,
|
|||
|
||||
include private.lexer
|
||||
include private.tagLibrary
|
||||
include private.events
|
||||
include private.sequential
|
||||
include private.json
|
||||
include private.dumper
|
|
@ -110,13 +110,6 @@ proc prepend*(event: YamlStreamEvent, s: YamlStream): YamlStream =
|
|||
for e in s():
|
||||
yield e
|
||||
|
||||
proc wrapWithDocument*(s: YamlStream): YamlStream =
|
||||
result = iterator(): YamlStreamEvent =
|
||||
yield YamlStreamEvent(kind: yamlStartDocument)
|
||||
for event in s():
|
||||
yield event
|
||||
yield YamlStreamEvent(kind: yamlEndDocument)
|
||||
|
||||
proc construct*(s: YamlStream, result: var string) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
|
@ -278,3 +271,21 @@ proc serialize*[K, V](value: Table[K, V],
|
|||
for event in events():
|
||||
yield event
|
||||
yield YamlStreamEvent(kind: yamlEndMap)
|
||||
|
||||
proc load*[K](input: Stream, target: var K) =
|
||||
var
|
||||
parser = newParser(coreTagLibrary())
|
||||
events = parser.parse(input)
|
||||
assert events().kind == yamlStartDocument
|
||||
construct(events, target)
|
||||
assert events().kind == yamlEndDocument
|
||||
|
||||
proc dump*[K](value: K, target: Stream, style: YamlDumpStyle = yDumpDefault,
|
||||
indentationStep: int = 2) =
|
||||
var serialized = serialize(value, style == yDumpCanonical)
|
||||
var events = iterator(): YamlStreamEvent =
|
||||
yield YamlStreamEvent(kind: yamlStartDocument)
|
||||
for event in serialized():
|
||||
yield event
|
||||
yield YamlStreamEvent(kind: yamlEndDocument)
|
||||
present(events, target, coreTagLibrary(), style, indentationStep)
|
Loading…
Reference in New Issue