mirror of https://github.com/status-im/NimYAML.git
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:
parent
d05971d5ac
commit
a08f4c1e4e
|
@ -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
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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:
|
||||
|
|
138
private/json.nim
138
private/json.nim
|
@ -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)
|
|
@ -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)
|
|
@ -1 +1 @@
|
|||
import parsing, serializing
|
||||
import parsing, constructingJson, serializing
|
99
yaml.nim
99
yaml.nim
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue