changed TagId to Tag. removed JS stuff that wasn't working anyway.

This commit is contained in:
Felix Krause 2020-11-10 13:55:22 +01:00
parent 6238104622
commit aa65c066d5
9 changed files with 185 additions and 292 deletions

View File

@ -118,7 +118,7 @@ template yieldEvent() {.dirty.} =
yield curEvent
inEvent = false
template setTag(t: TagId) {.dirty.} =
template setTag(t: Tag) {.dirty.} =
case curEvent.kind
of yamlStartSeq: curEvent.seqProperties.tag = t
of yamlStartMap: curEvent.mapProperties.tag = t
@ -133,8 +133,8 @@ template setAnchor(a: Anchor) {.dirty.} =
of yamlAlias: curEvent.aliasTarget = a
else: discard
template curTag(): TagId =
var foo: TagId
template curTag(): Tag =
var foo: Tag
case curEvent.kind
of yamlStartSeq: foo = curEvent.seqProperties.tag
of yamlStartMap: foo = curEvent.mapProperties.tag
@ -143,7 +143,7 @@ template curTag(): TagId =
$curEvent.kind & " may not have a tag")
foo
template setCurTag(val: TagId) =
template setCurTag(val: Tag) =
case curEvent.kind
of yamlStartSeq: curEvent.seqProperties.tag = val
of yamlStartMap: curEvent.mapProperties.tag = val

View File

@ -71,7 +71,7 @@ setTagUri(BetterInt, "!test:BetterInt")
const yamlDirs = "%YAML 1.2\n%TAG !n! tag:nimyaml.org,2016:\n--- "
proc representObject*(value: BetterInt, ts: TagStyle = tsNone,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
var
val = $value
i = val.len - 3

View File

@ -10,17 +10,8 @@ type
## Anchor provides the operator `$` for converting to string, `==` for
## comparison, and `hash` for usage in a hashmap.
TagId* = distinct int ## \
## A ``TagId`` identifies a tag URI, like for example
## ``"tag:yaml.org,2002:str"``. The URI corresponding to a ``TagId`` can
## be queried from the `TagLibrary <#TagLibrary>`_ which was
## used to create this ``TagId``; e.g. when you parse a YAML character
## stream, the ``TagLibrary`` of the parser is the one which generates
## the resulting ``TagId`` s.
##
## URI strings are mapped to ``TagId`` s for efficiency reasons (you
## do not need to compare strings every time) and to be able to
## discover unknown tag URIs early in the parsing process.
Tag* = distinct string ## \
## A ``Tag`` contains an URI, like for example ``"tag:yaml.org,2002:str"``.
ScalarStyle* = enum
## Original style of the scalar (for input),
@ -77,7 +68,21 @@ type
Mark* = tuple[line, column: Positive]
Properties* = tuple[anchor: Anchor, tag: TagId]
Properties* = tuple[anchor: Anchor, tag: Tag]
const
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
nimyamlTagRepositoryPrefix* = "tag:nimyaml.org,2016:"
proc defineTag*(uri: string): Tag =
## defines a tag. Use this to optimize away copies of globally defined
## Tags.
result = uri.Tag
#shallow(result.string) # doesn't work at compile-time
proc defineCoreTag*(name: string): Tag =
## defines a tag in YAML's core namespace, ``tag:yaml.org,2002:``
result = defineTag(yamlTagRepositoryPrefix & name)
const
yAnchorNone*: Anchor = "".Anchor ## \
@ -86,61 +91,36 @@ const
defaultMark: Mark = (1.Positive, 1.Positive) ## \
## used for events that are not generated from input.
yTagExclamationMark*: TagId = 0.TagId ## ``!`` non-specific tag
yTagQuestionMark* : TagId = 1.TagId ## ``?`` non-specific tag
yTagExclamationMark*: Tag = defineTag("!")
yTagQuestionMark* : Tag = defineTag("?")
# failsafe schema
yTagString* : TagId = 2.TagId ## \
## `!!str <http://yaml.org/type/str.html >`_ tag
yTagSequence* : TagId = 3.TagId ## \
## `!!seq <http://yaml.org/type/seq.html>`_ tag
yTagMapping* : TagId = 4.TagId ## \
## `!!map <http://yaml.org/type/map.html>`_ tag
yTagString* = defineCoreTag("str")
yTagSequence* = defineCoreTag("seq")
yTagMapping* = defineCoreTag("map")
# json & core schema
yTagNull* : TagId = 5.TagId ## \
## `!!null <http://yaml.org/type/null.html>`_ tag
yTagBoolean* : TagId = 6.TagId ## \
## `!!bool <http://yaml.org/type/bool.html>`_ tag
yTagInteger* : TagId = 7.TagId ## \
## `!!int <http://yaml.org/type/int.html>`_ tag
yTagFloat* : TagId = 8.TagId ## \
## `!!float <http://yaml.org/type/float.html>`_ tag
yTagNull* = defineCoreTag("null")
yTagBoolean* = defineCoreTag("bool")
yTagInteger* = defineCoreTag("int")
yTagFloat* = defineCoreTag("float")
# other language-independent YAML types (from http://yaml.org/type/ )
yTagOrderedMap* : TagId = 9.TagId ## \
## `!!omap <http://yaml.org/type/omap.html>`_ tag
yTagPairs* : TagId = 10.TagId ## \
## `!!pairs <http://yaml.org/type/pairs.html>`_ tag
yTagSet* : TagId = 11.TagId ## \
## `!!set <http://yaml.org/type/set.html>`_ tag
yTagBinary* : TagId = 12.TagId ## \
## `!!binary <http://yaml.org/type/binary.html>`_ tag
yTagMerge* : TagId = 13.TagId ## \
## `!!merge <http://yaml.org/type/merge.html>`_ tag
yTagTimestamp* : TagId = 14.TagId ## \
## `!!timestamp <http://yaml.org/type/timestamp.html>`_ tag
yTagValue* : TagId = 15.TagId ## \
## `!!value <http://yaml.org/type/value.html>`_ tag
yTagYaml* : TagId = 16.TagId ## \
## `!!yaml <http://yaml.org/type/yaml.html>`_ tag
yTagOrderedMap* = defineCoreTag("omap")
yTagPairs* = defineCoreTag("pairs")
yTagSet* = defineCoreTag("set")
yTagBinary* = defineCoreTag("binary")
yTagMerge* = defineCoreTag("merge")
yTagTimestamp* = defineCoreTag("timestamp")
yTagValue* = defineCoreTag("value")
yTagYaml* = defineCoreTag("yaml")
yTagNimField* : TagId = 100.TagId ## \
## This tag is used in serialization for the name of a field of an
## object. It may contain any string scalar that is a valid Nim symbol.
# NimYAML specific tags
yFirstStaticTagId* : TagId = 1000.TagId ## \
## The first ``TagId`` assigned by the ``setTagId`` templates.
yFirstCustomTagId* : TagId = 10000.TagId ## \
## The first ``TagId`` which should be assigned to an URI that does not
## exist in the ``YamlTagLibrary`` which is used for parsing.
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
nimyamlTagRepositoryPrefix* = "tag:nimyaml.org,2016:"
yTagNimField* = defineTag(nimyamlTagRepositoryPrefix & "field")
proc properties*(event: Event): Properties =
## returns the tag of the given event
@ -186,7 +166,7 @@ proc startMapEvent*(style: CollectionStyle, props: Properties,
mapStyle: style)
proc startMapEvent*(style: CollectionStyle = csAny,
tag: TagId = yTagQuestionMark,
tag: Tag = yTagQuestionMark,
anchor: Anchor = yAnchorNone,
startPos, endPos: Mark = defaultMark): Event {.inline.} =
return startMapEvent(style, (anchor, tag), startPos, endPos)
@ -204,7 +184,7 @@ proc startSeqEvent*(style: CollectionStyle,
seqStyle: style)
proc startSeqEvent*(style: CollectionStyle = csAny,
tag: TagId = yTagQuestionMark,
tag: Tag = yTagQuestionMark,
anchor: Anchor = yAnchorNone,
startPos, endPos: Mark = defaultMark): Event {.inline.} =
return startSeqEvent(style, (anchor, tag), startPos, endPos)
@ -221,7 +201,7 @@ proc scalarEvent*(content: string, props: Properties,
kind: yamlScalar, scalarProperties: props,
scalarContent: content, scalarStyle: style)
proc scalarEvent*(content: string = "", tag: TagId = yTagQuestionMark,
proc scalarEvent*(content: string = "", tag: Tag = yTagQuestionMark,
anchor: Anchor = yAnchorNone,
style: ScalarStyle = ssAny,
startPos, endPos: Mark = defaultMark): Event {.inline.} =
@ -231,34 +211,13 @@ proc aliasEvent*(target: Anchor, startPos, endPos: Mark = defaultMark): Event {.
## creates a new event that represents a YAML alias
result = Event(startPos: startPos, endPos: endPos, kind: yamlAlias, aliasTarget: target)
proc `==`*(left, right: Anchor): bool {.borrow, locks: 0.}
proc `$`*(id: Anchor): string {.borrow, locks: 0.}
proc hash*(id: Anchor): Hash {.borrow, locks: 0.}
proc `==`*(left, right: Anchor): bool {.borrow.}
proc `$`*(id: Anchor): string {.borrow.}
proc hash*(id: Anchor): Hash {.borrow.}
proc `==`*(left, right: TagId): bool {.borrow, locks: 0.}
proc hash*(id: TagId): Hash {.borrow, locks: 0.}
proc `$`*(id: TagId): string {.raises: [].} =
case id
of yTagQuestionMark: "?"
of yTagExclamationMark: "!"
of yTagString: "!!str"
of yTagSequence: "!!seq"
of yTagMapping: "!!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"
of yTagNimField: "!nim:field"
else: "<" & $int(id) & ">"
proc `==`*(left, right: Tag): bool {.borrow.}
proc `$`*(tag: Tag): string {.borrow.}
proc hash*(tag: Tag): Hash {.borrow.}
proc `==`*(left: Event, right: Event): bool {.raises: [].} =
## compares all existing fields of the given items
@ -279,8 +238,8 @@ proc renderAttrs*(props: Properties, isPlain: bool = true): string =
result = ""
if props.anchor != yAnchorNone: result &= " &" & $props.anchor
case props.tag
of yTagQuestionmark: discard
of yTagExclamationmark:
of yTagQuestionMark: discard
of yTagExclamationMark:
if isPlain: result &= " <!>"
else:
result &= " <" & $props.tag & ">"
@ -313,3 +272,14 @@ proc `$`*(event: Event): string {.raises: [].} =
of ssFolded: result &= " >"
result &= yamlTestSuiteEscape(event.scalarContent)
of yamlAlias: result = "=ALI *" & $event.aliasTarget
type
TypeID* = int ## unique ID of a type
var nextTypeID {.compileTime.}: TypeID
proc typeID*(T:typedesc): TypeID =
const id = nextTypeID
static:
inc nextTypeID
return id

View File

@ -137,11 +137,8 @@ proc composeNode(s: var YamlStream, tagLib: TagLibrary,
YamlNode {.raises: [YamlStreamError, YamlConstructionError].} =
template addAnchor(c: ConstructionContext, target: Anchor) =
if target != yAnchorNone:
when defined(JS):
{.emit: [c, """.refs.set(""", target, ", ", result, ");"].}
else:
yAssert(not c.refs.hasKey(target))
c.refs[target] = cast[pointer](result)
yAssert(not c.refs.hasKey(target))
c.refs[target] = (id: typeID(YamlNode), p: cast[pointer](result))
var start: Event
shallowCopy(start, s.next())
@ -149,7 +146,7 @@ proc composeNode(s: var YamlStream, tagLib: TagLibrary,
try:
case start.kind
of yamlStartMap:
result = YamlNode(tag: tagLib.uri(start.mapProperties.tag),
result = YamlNode(tag: $start.mapProperties.tag,
kind: yMapping,
fields: newTable[YamlNode, YamlNode]())
while s.peek().kind != yamlEndMap:
@ -162,7 +159,7 @@ proc composeNode(s: var YamlStream, tagLib: TagLibrary,
discard s.next()
addAnchor(c, start.mapProperties.anchor)
of yamlStartSeq:
result = YamlNode(tag: tagLib.uri(start.seqProperties.tag),
result = YamlNode(tag: $start.seqProperties.tag,
kind: ySequence,
elems: newSeq[YamlNode]())
while s.peek().kind != yamlEndSeq:
@ -170,15 +167,12 @@ proc composeNode(s: var YamlStream, tagLib: TagLibrary,
addAnchor(c, start.seqProperties.anchor)
discard s.next()
of yamlScalar:
result = YamlNode(tag: tagLib.uri(start.scalarProperties.tag),
result = YamlNode(tag: $start.scalarProperties.tag,
kind: yScalar)
shallowCopy(result.content, start.scalarContent)
addAnchor(c, start.scalarProperties.anchor)
of yamlAlias:
when defined(JS):
{.emit: [result, " = ", c, ".refs.get(", start.aliasTarget, ");"].}
else:
result = cast[YamlNode](c.refs[start.aliasTarget])
result = cast[YamlNode](c.refs[start.aliasTarget].p)
else: internalError("Malformed YamlStream")
except KeyError:
raise newException(YamlConstructionError,
@ -213,44 +207,22 @@ proc loadDom*(s: Stream | string): YamlDocument
proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle,
tagLib: TagLibrary) {.raises: [].}=
var val = yAnchorNone
when defined(JS):
{.emit: ["""
if (""", a, " != ", asNone, " && ", c, ".refs.has(", n, """) {
""", val, " = ", c, ".refs.get(", n, """);
if (""", c, ".refs.get(", n, ") == ", yAnchorNone, ") {"].}
val = c.nextAnchorId
{.emit: [c, """.refs.set(""", n, """, """, val, """);"""].}
c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1)
{.emit: "}".}
let p = cast[pointer](n)
if a != asNone and c.refs.hasKey(p):
val = c.refs.getOrDefault(p).a
if val == yAnchorNone:
val = c.nextAnchorId.Anchor
c.refs[p] = (val, false)
nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1)
c.put(aliasEvent(val))
return
{.emit: "}".}
else:
let p = cast[pointer](n)
if a != asNone and c.refs.hasKey(p):
val = c.refs.getOrDefault(p)
if val == yAnchorNone:
val = c.nextAnchorId.Anchor
c.refs[p] = val
nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1)
c.put(aliasEvent(val))
return
var
tagId: TagId
anchor: Anchor
if a == asAlways:
if a != asNone:
val = c.nextAnchorId.Anchor
when defined(JS):
{.emit: [c, ".refs.set(", n, ", ", val, ");"].}
else:
c.refs[p] = c.nextAnchorId.Anchor
c.refs[p] = (c.nextAnchorId.Anchor, false)
nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1)
else:
when defined(JS):
{.emit: [c, ".refs.set(", n, ", ", yAnchorNone, ");"].}
else:
c.refs[p] = yAnchorNone
tagId = if tagLib.tags.hasKey(n.tag): tagLib.tags.getOrDefault(n.tag) else:
let tag = if tagLib.tags.hasKey(n.tag): tagLib.tags.getOrDefault(n.tag) else:
tagLib.registerUri(n.tag)
case a
of asNone: anchor = yAnchorNone
@ -258,27 +230,25 @@ proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle,
of asAlways: anchor = val
case n.kind
of yScalar: c.put(scalarEvent(n.content, tagId, anchor))
of yScalar: c.put(scalarEvent(n.content, tag, anchor))
of ySequence:
c.put(startSeqEvent(csBlock, (anchor, tagId)))
c.put(startSeqEvent(csBlock, (anchor, tag)))
for item in n.elems:
serializeNode(item, c, a, tagLib)
c.put(endSeqEvent())
of yMapping:
c.put(startMapEvent(csBlock, (anchor, tagId)))
c.put(startMapEvent(csBlock, (anchor, tag)))
for key, value in n.fields.pairs:
serializeNode(key, c, a, tagLib)
serializeNode(value, c, a, tagLib)
c.put(endMapEvent())
template processAnchoredEvent(target: untyped, c: SerializationContext) =
var anchorId: Anchor
when defined(JS):
{.emit: [anchorId, " = ", c, ".refs.get(", target, ");"].}
else:
anchorId = c.refs.getOrDefault(cast[pointer](target.anchor))
if anchorId != yAnchorNone: target.anchor = anchorId
else: target.anchor = yAnchorNone
proc processAnchoredEvent(target: var Properties, c: SerializationContext) =
for key, val in c.refs:
if val.a == target.anchor:
if not val.referenced:
target.anchor = yAnchorNone
break
proc serialize*(doc: YamlDocument, tagLib: TagLibrary, a: AnchorStyle = asTidy):
YamlStream {.raises: [].} =

View File

@ -212,7 +212,7 @@ proc generateError(c: Context, message: string):
msg: message, parent: nil, mark: c.lex.curStartPos,
lineContent: c.lex.currentLine())
proc parseTag(c: Context): TagId =
proc parseTag(c: Context): Tag =
let handle = c.lex.fullLexeme()
var uri = c.resolveHandle(handle)
if uri == "":
@ -792,7 +792,7 @@ proc beforeBlockIndentation(c: Context, e: var Event): bool =
elif c.levels[^1].state == beforeBlockIndentation:
raise c.generateError("Unexpected double beforeBlockIndentation")
else:
raise c.generateError("Internal error (please report this bug)")
raise c.generateError("Internal error (please report this bug): unexpected state at endBlockNode")
c.popLevel()
c.popLevel()
case c.lex.cur

View File

@ -428,7 +428,7 @@ proc writeTagAndAnchor(c: Context, props: Properties) {.raises: [YamlPresenterOu
let t = c.target
try:
if props.tag notin [yTagQuestionMark, yTagExclamationMark]:
let tagUri = c.tagLib.uri(props.tag)
let tagUri = $props.tag
let (handle, length) = c.searchHandle(tagUri)
if length > 0:
t.append(handle)

View File

@ -25,16 +25,14 @@ export data, stream, macros, annotations, options
type
SerializationContext* = ref object
## Context information for the process of serializing YAML from Nim values.
when not defined(JS):
refs*: Table[pointer, Anchor] # `pointer` does not work with JS
refs*: Table[pointer, tuple[a: Anchor, referenced: bool]]
style: AnchorStyle
nextAnchorId*: string
put*: proc(e: Event) {.raises: [], closure.}
ConstructionContext* = ref object
## Context information for the process of constructing Nim values from YAML.
when not defined(JS):
refs*: Table[Anchor, pointer]
refs*: Table[Anchor, tuple[id: TypeID, p: pointer]]
YamlConstructionError* = object of YamlLoadingError
## Exception that may be raised when constructing data objects from a
@ -88,42 +86,35 @@ proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext)
proc newConstructionContext*(): ConstructionContext =
new(result)
when defined(JS):
{.emit: [result, """.refs = new Map();"""].}
else:
result.refs = initTable[Anchor, pointer]()
result.refs = initTable[Anchor, tuple[id: TypeID, p: pointer]]()
proc newSerializationContext*(s: AnchorStyle,
putImpl: proc(e: Event) {.raises: [], closure.}):
SerializationContext =
result = SerializationContext(style: s, nextAnchorId: "a",
put: putImpl)
when defined(JS):
{.emit: [result, """.refs = new Map();"""].}
else: result.refs = initTable[pointer, Anchor]()
result.refs = initTable[pointer, tuple[a: Anchor, referenced: bool]]()
template presentTag*(t: typedesc, ts: TagStyle): TagId =
## Get the TagId that represents the given type in the given style
template presentTag*(t: typedesc, ts: TagStyle): Tag =
## Get the Tag that represents the given type in the given style
if ts == tsNone: yTagQuestionMark else: yamlTag(t)
proc lazyLoadTag(uri: string): TagId {.inline, raises: [].} =
proc lazyLoadTag(uri: string): Tag {.inline, raises: [].} =
try: result = serializationTagLibrary.tags[uri]
except KeyError: result = serializationTagLibrary.registerUri(uri)
proc safeTagUri(id: TagId): string {.raises: [].} =
proc safeTagUri(tag: Tag): string {.raises: [].} =
try:
var
uri = serializationTagLibrary.uri(id)
i = 0
var uri = $tag
# '!' is not allowed inside a tag handle
if uri.len > 0 and uri[0] == '!': uri = uri[1..^1]
# ',' is not allowed after a tag handle in the suffix because it's a flow
# indicator
for c in uri.mitems():
if c == ',': c = ';'
inc(i)
for i in countup(0, uri.len - 1):
if uri[i] == ',': uri[i] = ';'
return uri
except KeyError: internalError("Unexpected KeyError for TagId " & $id)
except KeyError:
internalError("Unexpected KeyError for Tag " & $tag)
proc constructionError(s: YamlStream, mark: Mark, msg: string): ref YamlConstructionError =
result = newException(YamlConstructionError, msg)
@ -151,7 +142,7 @@ template constructScalarItem*(s: var YamlStream, i: untyped,
e.parent = getCurrentException()
raise e
proc yamlTag*(T: typedesc[string]): TagId {.inline, noSideEffect, raises: [].} =
proc yamlTag*(T: typedesc[string]): Tag {.inline, noSideEffect, raises: [].} =
yTagString
proc constructObject*(s: var YamlStream, c: ConstructionContext,
@ -162,7 +153,7 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
result = item.scalarContent
proc representObject*(value: string, ts: TagStyle,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
## represents a string as YAML scalar
c.put(scalarEvent(value, tag, yAnchorNone))
@ -217,12 +208,12 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
result = int(i32Result)
proc representObject*[T: int8|int16|int32|int64](value: T, ts: TagStyle,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
## represents an integer value as YAML scalar
c.put(scalarEvent($value, tag, yAnchorNone))
proc representObject*(value: int, tagStyle: TagStyle,
c: SerializationContext, tag: TagId)
c: SerializationContext, tag: Tag)
{.raises: [YamlStreamError], inline.}=
## represent an integer of architecture-defined length by casting it to int32.
## on 64-bit systems, this may cause a RangeDefect.
@ -265,12 +256,12 @@ when defined(JS):
result = $BiggestInt(x)
proc representObject*[T: uint8|uint16|uint32|uint64](value: T, ts: TagStyle,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
## represents an unsigned integer value as YAML scalar
c.put(scalarEvent($value, tag, yAnchorNone))
proc representObject*(value: uint, ts: TagStyle, c: SerializationContext,
tag: TagId) {.raises: [YamlStreamError], inline.} =
tag: Tag) {.raises: [YamlStreamError], inline.} =
## represent an unsigned integer of architecture-defined length by casting it
## to int32. on 64-bit systems, this may cause a RangeDefect.
try: c.put(scalarEvent($uint32(value), tag, yAnchorNone))
@ -299,7 +290,7 @@ proc constructObject*[T: float|float32|float64](
escape(item.scalarContent))
proc representObject*[T: float|float32|float64](value: T, ts: TagStyle,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
## represents a float value as YAML scalar
case value
of Inf: c.put(scalarEvent(".inf", tag))
@ -307,7 +298,7 @@ proc representObject*[T: float|float32|float64](value: T, ts: TagStyle,
of NaN: c.put(scalarEvent(".nan", tag))
else: c.put(scalarEvent($value, tag))
proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean
proc yamlTag*(T: typedesc[bool]): Tag {.inline, raises: [].} = yTagBoolean
proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var bool)
@ -322,7 +313,7 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
escape(item.scalarContent))
proc representObject*(value: bool, ts: TagStyle, c: SerializationContext,
tag: TagId) {.raises: [].} =
tag: Tag) {.raises: [].} =
## represents a bool value as a YAML scalar
c.put(scalarEvent(if value: "y" else: "n", tag, yAnchorNone))
@ -337,11 +328,11 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
else: result = item.scalarContent[0]
proc representObject*(value: char, ts: TagStyle, c: SerializationContext,
tag: TagId) {.raises: [].} =
tag: Tag) {.raises: [].} =
## represents a char value as YAML scalar
c.put(scalarEvent("" & value, tag, yAnchorNone))
proc yamlTag*(T: typedesc[Time]): TagId {.inline, raises: [].} = yTagTimestamp
proc yamlTag*(T: typedesc[Time]): Tag {.inline, raises: [].} = yTagTimestamp
proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var Time)
@ -403,15 +394,15 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
escape(item.scalarContent))
proc representObject*(value: Time, ts: TagStyle, c: SerializationContext,
tag: TagId) {.raises: [ValueError].} =
tag: Tag) {.raises: [ValueError].} =
let tmp = value.utc()
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]]): Tag {.inline, raises: [].} =
let uri = nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')')
result = lazyLoadTag(uri)
proc yamlTag*[I](T: typedesc[set[I]]): TagId {.inline, raises: [].} =
proc yamlTag*[I](T: typedesc[set[I]]): Tag {.inline, raises: [].} =
let uri = nimTag("system:set(" & safeTagUri(yamlTag(I)) & ')')
result = lazyLoadTag(uri)
@ -444,7 +435,7 @@ proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
discard s.next()
proc representObject*[T](value: seq[T]|set[T], ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
## represents a Nim seq as YAML sequence
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
c.put(startSeqEvent(tag = tag))
@ -452,7 +443,7 @@ proc representObject*[T](value: seq[T]|set[T], ts: TagStyle,
representChild(item, childTagStyle, c)
c.put(endSeqEvent())
proc yamlTag*[I, V](T: typedesc[array[I, V]]): TagId {.inline, raises: [].} =
proc yamlTag*[I, V](T: typedesc[array[I, V]]): Tag {.inline, raises: [].} =
const rangeName = name(I)
let uri = nimTag("system:array(" & rangeName[6..rangeName.high()] & ';' &
safeTagUri(yamlTag(V)) & ')')
@ -475,7 +466,7 @@ proc constructObject*[I, T](s: var YamlStream, c: ConstructionContext,
raise s.constructionError(event.startPos, "Too many array values")
proc representObject*[I, T](value: array[I, T], ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
## represents a Nim array as YAML sequence
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
c.put(startSeqEvent(tag = tag))
@ -483,7 +474,7 @@ proc representObject*[I, T](value: array[I, T], ts: TagStyle,
representChild(item, childTagStyle, c)
c.put(endSeqEvent())
proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline, raises: [].} =
proc yamlTag*[K, V](T: typedesc[Table[K, V]]): Tag {.inline, raises: [].} =
try:
let uri = nimTag("tables:Table(" & safeTagUri(yamlTag(K)) & ';' &
safeTagUri(yamlTag(V)) & ")")
@ -512,7 +503,7 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
discard s.next()
proc representObject*[K, V](value: Table[K, V], ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
## represents a Nim Table as YAML mapping
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
c.put(startMapEvent(tag = tag))
@ -521,7 +512,7 @@ proc representObject*[K, V](value: Table[K, V], ts: TagStyle,
representChild(value, childTagStyle, c)
c.put(endMapEvent())
proc yamlTag*[K, V](T: typedesc[OrderedTable[K, V]]): TagId
proc yamlTag*[K, V](T: typedesc[OrderedTable[K, V]]): Tag
{.inline, raises: [].} =
try:
let uri = nimTag("tables:OrderedTable(" & safeTagUri(yamlTag(K)) & ';' &
@ -557,7 +548,7 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
discard s.next()
proc representObject*[K, V](value: OrderedTable[K, V], ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
c.put(startSeqEvent(tag = tag))
for key, value in value.pairs:
@ -568,13 +559,13 @@ proc representObject*[K, V](value: OrderedTable[K, V], ts: TagStyle,
c.put(endSeqEvent())
proc yamlTag*(T: typedesc[object|enum]):
TagId {.inline, raises: [].} =
Tag {.inline, raises: [].} =
var uri = nimTag("custom:" & (typetraits.name(type(T))))
try: serializationTagLibrary.tags[uri]
except KeyError: serializationTagLibrary.registerUri(uri)
proc yamlTag*(T: typedesc[tuple]):
TagId {.inline, raises: [].} =
Tag {.inline, raises: [].} =
var
i: T
uri = nimTag("tuple(")
@ -999,7 +990,7 @@ macro genRepresentObject(t: typedesc, value, childTagStyle: typed) =
inc(fieldIndex)
proc representObject*[O: object](value: O, ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
## represents a Nim object or tuple as YAML mapping
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
when isVariantObject(getType(O)): c.put(startSeqEvent(tag = tag))
@ -1009,7 +1000,7 @@ proc representObject*[O: object](value: O, ts: TagStyle,
else: c.put(endMapEvent())
proc representObject*[O: tuple](value: O, ts: TagStyle,
c: SerializationContext, tag: TagId) =
c: SerializationContext, tag: Tag) =
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
var fieldIndex = 0'i16
c.put(startMapEvent(tag = tag))
@ -1035,13 +1026,13 @@ proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext,
raise ex
proc representObject*[O: enum](value: O, ts: TagStyle,
c: SerializationContext, tag: TagId) {.raises: [].} =
c: SerializationContext, tag: Tag) {.raises: [].} =
## represents a Nim enum as YAML scalar
c.put(scalarEvent($value, tag, yAnchorNone))
proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O)
proc yamlTag*[O](T: typedesc[ref O]): Tag {.inline, raises: [].} = yamlTag(O)
macro constructImplicitVariantObject(s, m, c, r, possibleTagIds: untyped,
macro constructImplicitVariantObject(s, m, c, r, possibleTags: untyped,
t: typedesc) =
let tDesc = getType(getType(t)[1])
yAssert tDesc.kind == nnkObjectTy
@ -1058,12 +1049,12 @@ macro constructImplicitVariantObject(s, m, c, r, possibleTagIds: untyped,
)))
case recCase[i][1].recListLen
of 0:
branch.add(infix(newIdentNode("yTagNull"), "in", possibleTagIds))
branch.add(infix(newIdentNode("yTagNull"), "in", possibleTags))
branchContent.add(newNimNode(nnkDiscardStmt).add(newCall("next", s)))
of 1:
let field = newDotExpr(r, newIdentNode($recCase[i][1].recListNode))
branch.add(infix(
newCall("yamlTag", newCall("type", field)), "in", possibleTagIds))
newCall("yamlTag", newCall("type", field)), "in", possibleTags))
branchContent.add(newCall("constructChild", s, c, field))
else:
block:
@ -1074,8 +1065,7 @@ macro constructImplicitVariantObject(s, m, c, r, possibleTagIds: untyped,
newCall(bindSym("constructionError"), s, m,
infix(newStrLitNode("This value type does not map to any field in " &
getTypeImpl(t)[1].repr & ": "), "&",
newCall("uri", newIdentNode("serializationTagLibrary"),
newNimNode(nnkBracketExpr).add(possibleTagIds, newIntLitNode(0)))
newCall("$", newNimNode(nnkBracketExpr).add(possibleTags, newIntLitNode(0)))
)
))
result.add(newNimNode(nnkElse).add(newNimNode(nnkTryStmt).add(
@ -1111,45 +1101,45 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
when isImplicitVariantObject(T):
when not canBeImplicit(T):
{. fatal: "This type cannot be marked as implicit" .}
var possibleTagIds = newSeq[TagId]()
var possibleTags = newSeq[Tag]()
case item.kind
of yamlScalar:
case item.scalarProperties.tag
of yTagQuestionMark:
case guessType(item.scalarContent)
of yTypeInteger:
possibleTagIds.add([yamlTag(int), yamlTag(int8), yamlTag(int16),
possibleTags.add([yamlTag(int), yamlTag(int8), yamlTag(int16),
yamlTag(int32), yamlTag(int64)])
if item.scalarContent[0] != '-':
possibleTagIds.add([yamlTag(uint), yamlTag(uint8), yamlTag(uint16),
possibleTags.add([yamlTag(uint), yamlTag(uint8), yamlTag(uint16),
yamlTag(uint32), yamlTag(uint64)])
of yTypeFloat, yTypeFloatInf, yTypeFloatNaN:
possibleTagIds.add([yamlTag(float), yamlTag(float32),
possibleTags.add([yamlTag(float), yamlTag(float32),
yamlTag(float64)])
of yTypeBoolTrue, yTypeBoolFalse:
possibleTagIds.add(yamlTag(bool))
possibleTags.add(yamlTag(bool))
of yTypeNull:
raise s.constructionError(item.startPos, "not implemented!")
of yTypeUnknown:
possibleTagIds.add(yamlTag(string))
possibleTags.add(yamlTag(string))
of yTypeTimestamp:
possibleTagIds.add(yamlTag(Time))
possibleTags.add(yamlTag(Time))
of yTagExclamationMark:
possibleTagIds.add(yamlTag(string))
possibleTags.add(yamlTag(string))
else:
possibleTagIds.add(item.scalarProperties.tag)
possibleTags.add(item.scalarProperties.tag)
of yamlStartMap:
if item.mapProperties.tag in [yTagQuestionMark, yTagExclamationMark]:
raise s.constructionError(item.startPos,
"Complex value of implicit variant object type must have a tag.")
possibleTagIds.add(item.mapProperties.tag)
possibleTags.add(item.mapProperties.tag)
of yamlStartSeq:
if item.seqProperties.tag in [yTagQuestionMark, yTagExclamationMark]:
raise s.constructionError(item.startPos,
"Complex value of implicit variant object type must have a tag.")
possibleTagIds.add(item.seqProperties.tag)
possibleTags.add(item.seqProperties.tag)
else: internalError("Unexpected item kind: " & $item.kind)
constructImplicitVariantObject(s, item.startPos, c, result, possibleTagIds, T)
constructImplicitVariantObject(s, item.startPos, c, result, possibleTags, T)
else:
case item.kind
of yamlScalar:
@ -1233,20 +1223,14 @@ proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
discard s.next()
return
elif e.kind == yamlAlias:
when defined(JS):
{.emit: [result, """ = """, c, """.refs.get(""", e.aliasTarget, """);"""].}
else:
result = cast[ref O](c.refs.getOrDefault(e.aliasTarget))
result = cast[ref O](c.refs.getOrDefault(e.aliasTarget).p)
discard s.next()
return
new(result)
template removeAnchor(anchor: var Anchor) {.dirty.} =
if anchor != yAnchorNone:
when defined(JS):
{.emit: [c, """.refs.set(""", anchor, """, """, result, """);"""].}
else:
yAssert(not c.refs.hasKey(anchor))
c.refs[anchor] = cast[pointer](result)
yAssert(not c.refs.hasKey(anchor))
c.refs[anchor] = (0, cast[pointer](result))
anchor = yAnchorNone
case e.kind
@ -1280,50 +1264,33 @@ proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext) =
if isNil(value): c.put(scalarEvent("~", yTagNull))
elif c.style == asNone: representChild(value[], ts, c)
else:
var val: Anchor
when defined(JS):
{.emit: ["""
if (""", c, """.refs.has(""", value, """) {
""", val, """ = """, c, """.refs.get(""", value, """);
if (val == """, yAnchorNone, ") {"].}
val = c.nextAnchorId
{.emit: [c, """.refs.set(""", value, """, """, val, """);"""].}
nextAnchor(c, len(c.nextAnchorId) - 1)
{.emit: "}".}
c.put(aliasEvent(val))
var val: tuple[a: Anchor, referenced: bool]
let p = cast[pointer](value)
if c.refs.hasKey(p):
val = c.refs.getOrDefault(p)
yAssert(val.a != yAnchorNone)
if not val.referenced:
c.refs[p] = (val.a, true)
c.put(aliasEvent(val.a))
return
else:
let p = cast[pointer](value)
if c.refs.hasKey(p):
val = c.refs.getOrDefault(p)
if val == yAnchorNone:
val = c.nextAnchorId.Anchor
c.refs[p] = val
nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1)
c.put(aliasEvent(val))
return
if c.style == asAlways:
val = c.nextAnchorId.Anchor
when defined(JS):
{.emit: [c, ".refs.set(", p, ", ", val, ");"].}
else: c.refs[p] = val
if c.style != asNone:
val = (c.nextAnchorId.Anchor, false)
c.refs[p] = val
nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1)
else: c.refs[p] = yAnchorNone
let
a = if c.style == asAlways: val else: cast[Anchor](p)
childTagStyle = if ts == tsAll: tsAll else: tsRootOnly
origPut = c.put
c.put = proc(e: Event) =
var ex = e
case ex.kind
of yamlStartMap:
ex.mapProperties.anchor = a
ex.mapProperties.anchor = val.a
if ts == tsNone: ex.mapProperties.tag = yTagQuestionMark
of yamlStartSeq:
ex.seqProperties.anchor = a
ex.seqProperties.anchor = val.a
if ts == tsNone: ex.seqProperties.tag = yTagQuestionMark
of yamlScalar:
ex.scalarProperties.anchor = a
ex.scalarProperties.anchor = val.a
if ts == tsNone and guessType(ex.scalarContent) != yTypeNull:
ex.scalarProperties.tag = yTagQuestionMark
else: discard
@ -1401,6 +1368,10 @@ proc load*[K](input: Stream | string, target: var K)
elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent)
else: internalError("Unexpected exception: " & $e.parent.name)
proc loadAs*[K](input: string): K {.raises: [YamlConstructionError, IOError, YamlParserError].} =
## Loads the given YAML input to a value of the type K and returns it
load(input, result)
proc loadMultiDoc*[K](input: Stream | string, target: var seq[K]) =
var
parser = initYamlParser(serializationTagLibrary)
@ -1427,10 +1398,10 @@ proc loadMultiDoc*[K](input: Stream | string, target: var seq[K]) =
proc setAnchor(a: var Anchor, c: var SerializationContext)
{.inline.} =
if a != yAnchorNone:
when defined(JS):
{.emit: [a, """ = """, c, """.refs.get(""", a, """);"""].}
else:
a = c.refs.getOrDefault(cast[pointer](a))
for key, val in c.refs:
if val.a == a:
if not val.referenced: a = yAnchorNone
return
proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
a: AnchorStyle = asTidy): YamlStream =

View File

@ -28,29 +28,19 @@ type
## them with `initFailsafeTagLibrary <#initFailsafeTagLibrary>`_,
## `initCoreTagLibrary <#initCoreTagLibrary>`_ or
## `initExtendedTagLibrary <#initExtendedTagLibrary>`_.
tags*: Table[string, TagId]
nextCustomTagId*: TagId
tags*: Table[string, Tag]
proc initTagLibrary*(): TagLibrary {.raises: [].} =
## initializes the ``tags`` table and sets ``nextCustomTagId`` to
## ``yFirstCustomTagId``.
new(result)
result.tags = initTable[string, TagId]()
result.tags = initTable[string, Tag]()
result.nextCustomTagId = yFirstCustomTagId
proc registerUri*(tagLib: TagLibrary, uri: string): TagId {.raises: [].} =
proc registerUri*(tagLib: TagLibrary, uri: string): Tag {.raises: [].} =
## registers a custom tag URI with a ``TagLibrary``. The URI will get
## the ``TagId`` ``nextCustomTagId``, which will be incremented.
tagLib.tags[uri] = tagLib.nextCustomTagId
result = tagLib.nextCustomTagId
tagLib.nextCustomTagId = cast[TagId](cast[int](tagLib.nextCustomTagId) + 1)
proc uri*(tagLib: TagLibrary, id: TagId): string {.raises: [KeyError].} =
## retrieve the URI a ``TagId`` maps to.
for iUri, iId in tagLib.tags.pairs:
if iId == id: return iUri
raise newException(KeyError, "Unknown tag id: " & $id)
result = uri.Tag
tagLib.tags[uri] = result
template y(suffix: string): string = yamlTagRepositoryPrefix & suffix
template n(suffix: string): string = nimyamlTagRepositoryPrefix & suffix
@ -114,7 +104,7 @@ proc initSerializationTagLibrary*(): TagLibrary =
result.tags[n"field"] = yTagNimField
var
serializationTagLibrary* = initSerializationTagLibrary() ## \
serializationTagLibrary* {.compileTime.} = initSerializationTagLibrary() ## \
## contains all local tags that are used for type serialization. Does
## not contain any of the specific default tags for sequences or maps,
## as those are not suited for Nim's static type system.
@ -123,8 +113,6 @@ var
## `serializable <#serializable,stmt,stmt>`_.
var
nextStaticTagId {.compileTime.} = yFirstStaticTagId ## \
## used for generating unique TagIds with ``setTagUri``.
registeredUris {.compileTime.} = newSeq[string]() ## \
## Since Table doesn't really work at compile time, we also store
## registered URIs here to be able to generate a static compiler error
@ -135,14 +123,11 @@ template setTagUri*(t: typedesc, uri: string) =
## when loading and dumping values of this type.
when uri in registeredUris:
{. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .}
const id {.genSym.} = nextStaticTagId
const tag {.genSym.} = uri.Tag
static:
registeredUris.add(uri)
nextStaticTagId = TagId(int(nextStaticTagId) + 1)
when nextStaticTagId == yFirstCustomTagId:
{.fatal: "Too many tags!".}
serializationTagLibrary.tags[uri] = id
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = id
serializationTagLibrary.tags[uri] = tag
proc yamlTag*(T: typedesc[t]): Tag {.inline, raises: [].} = tag
## autogenerated
template setTagUri*(t: typedesc, uri: string, idName: untyped) =
@ -151,14 +136,11 @@ template setTagUri*(t: typedesc, uri: string, idName: untyped) =
## necessary if you want to implement serialization / construction yourself.
when uri in registeredUris:
{. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .}
const idName* = nextStaticTagId
const idName* = uri.Tag
static:
registeredUris.add(uri)
nextStaticTagId = TagId(int(nextStaticTagId) + 1)
when nextStaticTagId == yFirstCustomTagId:
{.fatal: "Too many tags!".}
serializationTagLibrary.tags[uri] = idName
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = idName
proc yamlTag*(T: typedesc[t]): Tag {.inline, raises: [].} = idName
## autogenerated
static:

View File

@ -21,7 +21,7 @@ type Level = tuple[node: JsonNode, key: string, expKey: bool]
proc initLevel(node: JsonNode): Level {.raises: [].} =
(node: node, key: "", expKey: true)
proc jsonFromScalar(content: string, tag: TagId): JsonNode
proc jsonFromScalar(content: string, tag: Tag): JsonNode
{.raises: [YamlConstructionError].}=
new(result)
var mappedType: TypeHint