Sanitized exceptions and raises pragmas

* Added raises pragma to every proc in yaml.nim
 * Properly encapsulate exceptions from YamlStreams
 * Discovered a Nim compiler bug and added a workaround
 * Added possibility to query line, column and line content from
   YamlParser
 * Updated rst documentation
 * Actually call callback in fastparse if available
 * Fixed parsing YAML version
This commit is contained in:
Felix Krause 2016-01-24 18:24:09 +01:00
parent d05971d5ac
commit a08f4c1e4e
7 changed files with 251 additions and 136 deletions

View File

@ -208,11 +208,8 @@ Output:
* Documentation:
- Document yaml.serialization
- Setup github pages site with proper API documentation
* Lexer:
- Add type hints for more scalar types
* Parser:
- Properly handle leading spaces in block scalars
* Serialization:
- Support for more standard library types
- Support for ref and ptr types

View File

@ -44,6 +44,15 @@ proc newYamlParser*(tagLib: TagLibrary = initExtendedTagLibrary(),
result.tagLib = tagLib
result.callback = callback
proc getLineNumber*(p: YamlParser): int = p.lexer.lineNumber
proc getColNumber*(p: YamlParser): int = p.tokenstart + 1 # column is 1-based
proc getLineContent*(p: YamlParser, marker: bool = true): string =
result = p.lexer.getCurrentLine(false)
if marker:
result.add(repeat(' ', p.tokenstart) & "^\n")
template debug(message: string) {.dirty.} =
when defined(yamlDebug):
try: styledWriteLine(stdout, fgBlue, message)
@ -52,15 +61,14 @@ template debug(message: string) {.dirty.} =
template parserError(message: string) {.dirty.} =
var e = newException(YamlParserError, message)
e.line = p.lexer.lineNumber
e.column = p.tokenstart
e.lineContent = p.lexer.getCurrentLine(false) &
repeat(' ', p.tokenstart) & "^\n"
e.column = p.tokenstart + 1
e.lineContent = p.getLineContent(true)
raise e
template lexerError(lx: BaseLexer, message: string) {.dirty.} =
var e = newException(YamlParserError, message)
e.line = lx.lineNumber
e.column = lx.bufpos
e.column = lx.bufpos + 1
e.lineContent = lx.getCurrentLine(false) &
repeat(' ', lx.getColNumber(lx.bufpos)) & "^\n"
raise e
@ -408,12 +416,18 @@ template yamlVersion(lexer: BaseLexer, o: var string) =
c = lexer.buf[lexer.bufpos]
if lexer.buf[lexer.bufpos] != '.':
lexerError(lexer, "Invalid YAML version number")
o.add('.')
lexer.bufpos.inc()
if lexer.buf[lexer.bufpos] notin digits:
c = lexer.buf[lexer.bufpos]
if c notin digits:
lexerError(lexer, "Invalid YAML version number")
o.add(c)
lexer.bufpos.inc()
while lexer.buf[lexer.bufpos] in digits:
c = lexer.buf[lexer.bufpos]
while c in digits:
o.add(c)
lexer.bufpos.inc()
c = lexer.buf[lexer.bufpos]
if lexer.buf[lexer.bufpos] notin spaceOrLineEnd:
lexerError(lexer, "Invalid YAML version number")
@ -1006,8 +1020,10 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
startToken()
p.lexer.yamlVersion(version)
if version != "1.2":
echo "version is not 1.2!"
# TODO: warning (unknown version)
if p.callback != nil:
p.callback(p.lexer.lineNumber, p.getColNumber(),
p.getLineContent(),
"Version is not 1.2, but " & version)
discard
p.lexer.lineEnding()
handleLineEnd(false)
@ -1020,7 +1036,9 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
p.lexer.lineEnding()
handleLineEnd(false)
of ldUnknown:
# TODO: warning (unknown directive)
if p.callback != nil:
p.callback(p.lexer.lineNumber, p.getColNumber(),
p.getLineContent(), "Unknown directive")
p.lexer.finishLine()
handleLineEnd(false)
of ' ', '\t':

View File

@ -62,11 +62,11 @@ macro typeHintStateMachine(c: untyped, content: untyped): stmt =
newIdentNode("typeHintState"), copyNimTree(rule[2]))))
stateBranches.add(stateBranch)
stateBranches.add(newNimNode(nnkElse).add(newStmtList(
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeString")))))
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown")))))
charBranch.add(newStmtList(stateBranches))
result.add(charBranch)
result.add(newNimNode(nnkElse).add(newStmtList(
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeString")))))
newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown")))))
template advanceTypeHint(ch: char) {.dirty.} =
typeHintStateMachine ch:

View File

@ -7,9 +7,11 @@
type
Level = tuple[node: JsonNode, key: string]
proc initLevel(node: JsonNode): Level = (node: node, key: cast[string](nil))
proc initLevel(node: JsonNode): Level {.raises: [].} =
(node: node, key: cast[string](nil))
proc jsonFromScalar(content: string, tag: TagId): JsonNode =
proc jsonFromScalar(content: string, tag: TagId): JsonNode
{.raises: [YamlConstructionError].}=
new(result)
var mappedType: TypeHint
@ -17,7 +19,7 @@ proc jsonFromScalar(content: string, tag: TagId): JsonNode =
of yTagQuestionMark:
mappedType = guessType(content)
of yTagExclamationMark, yTagString:
mappedType = yTypeString
mappedType = yTypeUnknown
of yTagBoolean:
case guessType(content)
of yTypeBoolTrue:
@ -25,41 +27,56 @@ proc jsonFromScalar(content: string, tag: TagId): JsonNode =
of yTypeBoolFalse:
mappedType = yTypeBoolFalse
else:
raise newException(ValueError, "Invalid boolean value: " & content)
raise newException(YamlConstructionError,
"Invalid boolean value: " & content)
of yTagInteger:
mappedType = yTypeInteger
of yTagNull:
mappedType = yTypeNull
of yTagFloat:
mappedType = yTypeFloat
## TODO: NaN, inf
case guessType(content)
of yTypeFloat:
mappedType = yTypeFloat
of yTypeFloatInf:
mappedType = yTypeFloatInf
of yTypeFloatNaN:
mappedType = yTypeFloatNaN
else:
raise newException(YamlConstructionError,
"Invalid float value: " & content)
else:
mappedType = yTypeUnknown
case mappedType
of yTypeInteger:
result.kind = JInt
result.num = parseBiggestInt(content)
of yTypeFloat:
result.kind = JFloat
result.fnum = parseFloat(content)
of yTypeFloatInf:
result.kind = JFloat
result.fnum = if content[0] == '-': NegInf else: Inf
of yTypeFloatNaN:
result.kind = JFloat
result.fnum = NaN
of yTypeBoolTrue:
result.kind = JBool
result.bval = true
of yTypeBoolFalse:
result.kind = JBool
result.bval = false
of yTypeNull:
result.kind = JNull
else:
result.kind = JString
result.str = content
try:
case mappedType
of yTypeInteger:
result.kind = JInt
result.num = parseBiggestInt(content)
of yTypeFloat:
result.kind = JFloat
result.fnum = parseFloat(content)
of yTypeFloatInf:
result.kind = JFloat
result.fnum = if content[0] == '-': NegInf else: Inf
of yTypeFloatNaN:
result.kind = JFloat
result.fnum = NaN
of yTypeBoolTrue:
result.kind = JBool
result.bval = true
of yTypeBoolFalse:
result.kind = JBool
result.bval = false
of yTypeNull:
result.kind = JNull
else:
result.kind = JString
result.str = content
except ValueError:
var e = newException(YamlConstructionError,
"Cannot parse numeric value")
e.parent = getCurrentException()
raise e
proc constructJson*(s: YamlStream): seq[JsonNode] =
newSeq(result, 0)
@ -67,8 +84,19 @@ proc constructJson*(s: YamlStream): seq[JsonNode] =
var
levels = newSeq[Level]()
anchors = initTable[AnchorId, JsonNode]()
for event in s():
safeIter = iterator(): YamlStreamEvent
{.raises: [YamlConstructionStreamError].} =
while true:
var item: YamlStreamEvent
try:
item = s()
if finished(s): break
except Exception:
var e = newException(YamlConstructionStreamError, "")
e.parent = getCurrentException()
raise e
yield item
for event in safeIter():
case event.kind
of yamlStartDocument:
# we don't need to do anything here; root node will be created
@ -104,7 +132,7 @@ proc constructJson*(s: YamlStream): seq[JsonNode] =
# JSON only allows strings as keys
levels[levels.high].key = event.scalarContent
if event.scalarAnchor != yAnchorNone:
raise newException(ValueError,
raise newException(YamlConstructionError,
"scalar keys may not have anchors in JSON")
else:
let jsonScalar = jsonFromScalar(event.scalarContent,
@ -125,7 +153,7 @@ proc constructJson*(s: YamlStream): seq[JsonNode] =
of JObject:
if isNil(levels[levels.high].key):
echo level.node.pretty()
raise newException(ValueError,
raise newException(YamlConstructionError,
"non-scalar as key not allowed in JSON")
else:
levels[levels.high].node.fields.add(
@ -140,15 +168,26 @@ proc constructJson*(s: YamlStream): seq[JsonNode] =
# (else the parser would have already thrown an exception)
case levels[levels.high].node.kind
of JArray:
levels[levels.high].node.elems.add(anchors[event.aliasTarget])
try:
levels[levels.high].node.elems.add(
anchors[event.aliasTarget])
except KeyError:
# we can safely assume that this doesn't happen. It would
# have resulted in a parser error earlier.
assert(false)
of JObject:
if isNil(levels[levels.high].key):
raise newException(ValueError,
raise newException(YamlConstructionError,
"cannot use alias node as key in JSON")
else:
levels[levels.high].node.fields.add(
(key: levels[levels.high].key,
val: anchors[event.aliasTarget]))
try:
levels[levels.high].node.fields.add(
(key: levels[levels.high].key,
val: anchors[event.aliasTarget]))
except KeyError:
# we can safely assume that this doesn't happen. It would
# have resulted in a parser error earlier.
assert(false)
levels[levels.high].key = nil
else:
discard # will never happen
@ -157,4 +196,23 @@ proc loadToJson*(s: Stream): seq[JsonNode] =
var
parser = newYamlParser(initCoreTagLibrary())
events = parser.parse(s)
return constructJson(events)
try:
return constructJson(events)
except YamlConstructionError:
var e = cast[ref YamlConstructionError](getCurrentException())
e.line = parser.getLineNumber()
e.column = parser.getColNumber()
e.lineContent = parser.getLineContent()
raise e
except YamlConstructionStreamError:
let e = getCurrentException()
if e.parent is IOError:
raise cast[ref IOError](e.parent)
elif e.parent is YamlParserError:
raise cast[ref YamlParserError](e.parent)
else:
# can never happen
assert(false)
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)

View File

@ -27,7 +27,7 @@ proc writeDoubleQuoted(scalar: string, s: Stream)
s.write('"')
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
template safeWrite(s: string or char) {.dirty.} =
@ -35,7 +35,7 @@ template safeWrite(s: string or char) {.dirty.} =
target.write(s)
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
proc startItem(target: Stream, style: PresentationStyle, indentation: int,
@ -121,7 +121,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
discard # can never happen
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: TagLibrary,
@ -147,7 +147,7 @@ proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: TagLibrary,
target.write(' ')
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
@ -166,7 +166,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
cached.enqueue(item)
except:
var e = newException(YamlPresenterStreamError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
indentation = 0
levels = newSeq[DumperState]()
@ -184,7 +184,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
target.write("--- ")
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
of yamlScalar:
if levels.len == 0:
@ -229,7 +229,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
target.write(cast[byte]('a') + cast[byte](item.aliasTarget))
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
of yamlStartSequence:
var nextState: DumperState
@ -253,7 +253,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
break
except:
var e = newException(YamlPresenterStreamError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
nextState = if length <= 60: dFlowSequenceStart else:
dBlockSequenceItem
@ -318,7 +318,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
mps = mpNeedBlock
except:
var e = newException(YamlPresenterStreamError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
nextState = if mps == mpNeedBlock: dBlockMapValue else:
dBlockInlineMap
@ -384,7 +384,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
target.write(']')
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
if levels.len == 0 or levels[levels.high] notin
[dBlockExplicitMapKey, dBlockMapValue,
@ -418,7 +418,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
target.write('}')
except:
var e = newException(YamlPresenterOutputError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
if levels.len == 0 or levels[levels.high] notin
[dBlockExplicitMapKey, dBlockMapValue,
@ -444,7 +444,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
cached.enqueue(next)
except:
var e = newException(YamlPresenterStreamError, "")
e.cause = getCurrentException()
e.parent = getCurrentException()
raise e
safeWrite("...\x0A")
@ -454,37 +454,52 @@ proc transform*(input: Stream, output: Stream, style: PresentationStyle,
taglib = initExtendedTagLibrary()
parser = newYamlParser(tagLib)
events = parser.parse(input)
if style == psCanonical:
var specificTagEvents = iterator(): YamlStreamEvent =
for e in events():
var event = e
case event.kind
of yamlStartDocument, yamlEndDocument, yamlEndMap, yamlAlias,
yamlEndSequence:
discard
of yamlStartMap:
if event.mapTag in [yTagQuestionMark, yTagExclamationMark]:
event.mapTag = yTagMap
of yamlStartSequence:
if event.seqTag in [yTagQuestionMark, yTagExclamationMark]:
event.seqTag = yTagSequence
of yamlScalar:
if event.scalarTag == yTagQuestionMark:
case guessType(event.scalarContent)
of yTypeInteger:
event.scalarTag = yTagInteger
of yTypeFloat, yTypeFloatInf, yTypeFloatNaN:
event.scalarTag = yTagFloat
of yTypeBoolTrue, yTypeBoolFalse:
event.scalarTag = yTagBoolean
of yTypeNull:
event.scalarTag = yTagNull
of yTypeString, yTypeUnknown:
try:
if style == psCanonical:
var specificTagEvents = iterator(): YamlStreamEvent =
for e in events():
var event = e
case event.kind
of yamlStartDocument, yamlEndDocument, yamlEndMap,
yamlAlias, yamlEndSequence:
discard
of yamlStartMap:
if event.mapTag in [yTagQuestionMark,
yTagExclamationMark]:
event.mapTag = yTagMap
of yamlStartSequence:
if event.seqTag in [yTagQuestionMark,
yTagExclamationMark]:
event.seqTag = yTagSequence
of yamlScalar:
if event.scalarTag == yTagQuestionMark:
case guessType(event.scalarContent)
of yTypeInteger:
event.scalarTag = yTagInteger
of yTypeFloat, yTypeFloatInf, yTypeFloatNaN:
event.scalarTag = yTagFloat
of yTypeBoolTrue, yTypeBoolFalse:
event.scalarTag = yTagBoolean
of yTypeNull:
event.scalarTag = yTagNull
of yTypeUnknown:
event.scalarTag = yTagString
elif event.scalarTag == yTagExclamationMark:
event.scalarTag = yTagString
elif event.scalarTag == yTagExclamationMark:
event.scalarTag = yTagString
yield event
present(specificTagEvents, output, tagLib, style,
indentationStep)
else:
present(events, output, tagLib, style, indentationStep)
yield event
present(specificTagEvents, output, tagLib, style,
indentationStep)
else:
present(events, output, tagLib, style, indentationStep)
except YamlPresenterStreamError:
let e = getCurrentException()
if e.parent is IOError:
raise cast[ref IOError](e.parent)
elif e.parent is YamlParserError:
raise cast[ref YamlParserError](e.parent)
else:
# never happens
assert(false)
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)

View File

@ -1 +1 @@
import parsing, serializing
import parsing, constructingJson, serializing

View File

@ -25,10 +25,13 @@ when defined(yamlDebug):
type
TypeHint* = enum
## A type hint is a friendly message from the YAML lexer, telling you
## it thinks a scalar string probably is of a certain type. You are not
## required to adhere to this information. The first matching RegEx will
## be the type hint of a scalar string.
## 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,TypeHint>`_ 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.
##
## ================== =========================
## Name RegEx
@ -40,14 +43,10 @@ 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``
## ``yTypeString`` *none*
## ``yTypeUnknown`` ``*``
## ================== =========================
##
## The value `yTypeString` is not returned based on RegExes, but for
## scalars that are quoted within the YAML input character stream.
yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue,
yTypeBoolFalse, yTypeNull, yTypeString, yTypeUnknown
yTypeBoolFalse, yTypeNull, yTypeUnknown
YamlStreamEventKind* = enum
## Kinds of YAML events that may occur in an ``YamlStream``. Event kinds
@ -59,11 +58,13 @@ type
## 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`` with
## `uri <#uri,TagLibrary,TagId>`_. 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.
## 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.
AnchorId* = distinct int ## \
## An ``AnchorId`` identifies an anchor in the current document. It
@ -105,7 +106,8 @@ type
## ``YamlStreamEvents``. Well-formed means that every ``yamlStartMap``
## is terminated by a ``yamlEndMap``, every ``yamlStartSequence`` is
## terminated by a ``yamlEndSequence`` and every ``yamlStartDocument``
## is terminated by a ``yamlEndDocument``.
## is terminated by a ``yamlEndDocument``. Moreover, every emitted map
## has an even number of children.
##
## The creator of a ``YamlStream`` is responsible for it being
## well-formed. A user of the stream may assume that it is well-formed
@ -122,8 +124,14 @@ type
## `extendedTagLibrary <#extendedTagLibrary>`_.
##
## When `YamlParser <#YamlParser>`_ encounters tags not existing in the
## tag library, it will assign ``nextCustomTagId`` to the URI, add it
## to the tag library and increase ``nextCustomTagId``.
## tag library, it will use
## `registerTagUri <#registerTagUri,TagLibrary,string,TagId>`_ to add
## the tag to the library.
##
## You can base your tag library on common tag libraries by initializing
## them with `initFailsafeTagLibrary <#initFailsafeTagLibrary>`_,
## `initCoreTagLibrary <#initCoreTagLibrary>`_ or
## `initExtendedTagLibrary <#initExtendedTagLibrary>`_.
tags*: Table[string, TagId]
nextCustomTagId*: TagId
secondaryPrefix*: string
@ -179,7 +187,7 @@ type
lineContent*: string ## \
## content of the line where the error was encountered. Includes a
## second line with a marker ``^`` at the position where the error
## was encountered, as returned by ``lexbase.getCurrentLine``.
## was encountered.
YamlParserError* = object of YamlLoadingError
## A parser error is raised if the character stream that is parsed is
@ -223,16 +231,26 @@ type
YamlPresenterOutputError* = object of Exception
## Exception that may be raised by the YAML presenter. This occurs if
## writing character data to the output stream raises any exception. The
## exception that has been catched is retrievable from ``cause``.
cause*: ref Exception
## writing character data to the output stream raises any exception.
## The error that has occurred is available from ``parent``.
YamlPresenterStreamError* = object of Exception
## Exception that may be raised by the YAML presenter. This occurs if
## an exception is raised while retrieving the next item from a
## `YamlStream <#YamlStream>`_. The exception that has been catched is
## retrievable from ``cause``.
cause*: ref Exception
## `YamlStream <#YamlStream>`_. The error that has occurred is
## available from ``parent``.
YamlConstructionError* = object of YamlLoadingError
## Exception that may be raised when constructing data objects from a
## `YamlStream <#YamlStream>`_. The fields ``line``, ``column`` and
## ``lineContent`` are only available if the costructing proc also does
## parsing, because otherwise this information is not available to the
## costruction proc.
YamlConstructionStreamError* = object of YamlLoadingError
## Exception that may be raised by a constructor if the input
## `YamlStream <#YamlStream>`_ raises an error. The error that has
## occurred is available from ``parent``.
const
# failsafe schema
@ -286,10 +304,10 @@ const
# interface
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].}
## compares all existing fields of the given items
proc `$`*(event: YamlStreamEvent): string
proc `$`*(event: YamlStreamEvent): string {.raises: [].}
## outputs a human-readable string describing the given event
proc startDocEvent*(): YamlStreamEvent {.inline, raises: [].}
@ -315,34 +333,34 @@ proc `==`*(left, right: AnchorId): bool {.borrow.}
proc `$`*(id: AnchorId): string {.borrow.}
proc hash*(id: AnchorId): Hash {.borrow.}
proc initTagLibrary*(): TagLibrary
proc initTagLibrary*(): TagLibrary {.raises: [].}
## initializes the ``tags`` table and sets ``nextCustomTagId`` to
## ``yFirstCustomTagId``.
proc registerUri*(tagLib: TagLibrary, uri: string): TagId
proc registerUri*(tagLib: TagLibrary, uri: string): TagId {.raises: [].}
## registers a custom tag URI with a ``TagLibrary``. The URI will get
## the ``TagId`` ``nextCustomTagId``, which will be incremented.
proc uri*(tagLib: TagLibrary, id: TagId): string
proc uri*(tagLib: TagLibrary, id: TagId): string {.raises: [KeyError].}
## retrieve the URI a ``TagId`` maps to.
# these should be consts, but the Nim VM still has problems handling tables
# properly, so we use let instead.
proc initFailsafeTagLibrary*(): TagLibrary
proc initFailsafeTagLibrary*(): TagLibrary {.raises: [].}
## Contains only:
## - ``!``
## - ``?``
## - ``!!str``
## - ``!!map``
## - ``!!seq``
proc initCoreTagLibrary*(): TagLibrary
proc initCoreTagLibrary*(): TagLibrary {.raises: [].}
## Contains everything in ``initFailsafeTagLibrary`` plus:
## - ``!!null``
## - ``!!bool``
## - ``!!int``
## - ``!!float``
proc initExtendedTagLibrary*(): TagLibrary
proc initExtendedTagLibrary*(): TagLibrary {.raises: [].}
## Contains everything from ``initCoreTagLibrary`` plus:
## - ``!!omap``
## - ``!!pairs``
@ -356,12 +374,17 @@ proc initExtendedTagLibrary*(): TagLibrary
proc guessType*(scalar: string): TypeHint {.raises: [].}
proc newYamlParser*(tagLib: TagLibrary = initExtendedTagLibrary(),
callback: WarningCallback = nil): YamlParser
callback: WarningCallback = nil): YamlParser {.raises: [].}
proc getLineNumber*(p: YamlParser): int {.raises: [].}
proc getColNumber*(p: YamlParser): int {.raises: [].}
proc getLineContent*(p: YamlParser, marker: bool = true): string {.raises: [].}
proc parse*(p: YamlParser, s: Stream):
YamlStream {.raises: [IOError, YamlParserError].}
proc constructJson*(s: YamlStream): seq[JsonNode]
{.raises: [YamlConstructionError, YamlConstructionStreamError].}
## Construct an in-memory JSON tree from a YAML event stream. The stream may
## not contain any tags apart from those in ``coreTagLibrary``. Anchors and
## aliases will be resolved. Maps in the input must not contain
@ -376,7 +399,8 @@ proc constructJson*(s: YamlStream): seq[JsonNode]
## of these values into a JSON character stream.
proc loadToJson*(s: Stream): seq[JsonNode]
## Uses `YamlSequentialParser <#YamlSequentialParser>`_ and
{.raises: [IOError, YamlParserError, YamlConstructionError].}
## Uses `YamlParser <#YamlParser>`_ and
## `constructJson <#constructJson>`_ to construct an in-memory JSON tree
## from a YAML character stream.
@ -388,9 +412,12 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
## Convert ``s`` to a YAML character stream and write it to ``target``.
proc transform*(input: Stream, output: Stream, style: PresentationStyle,
indentationStep: int = 2)
indentationStep: int = 2) {.raises: [IOError, YamlParserError,
YamlPresenterJsonError,
YamlPresenterOutputError].}
## Parser ``input`` as YAML character stream and then dump it to ``output``
## without resolving any tags, anchors and aliases.
## while resolving non-specific tags to the ones in the YAML core tag
## library.
# implementation