Finished JSON parser. Restructuring.

* Made JSON parser resolve anchors and aliases
 * Moved exported consts and types to yaml.nim
This commit is contained in:
Felix Krause 2015-12-26 13:16:57 +01:00
parent c83d488886
commit 2c4e681f0b
5 changed files with 67 additions and 44 deletions

8
.gitignore vendored
View File

@ -1,6 +1,8 @@
nimcache nimcache
nakefile nakefile
test/tests test/tests
test/tests.exe test/parsing
test/tests.pdb test/lexing
test/tests.ilk test/*.exe
test/*.pdb
test/*.ilk

View File

@ -1,7 +1,7 @@
type type
Level = tuple[node: JsonNode, key: string] Level = tuple[node: JsonNode, key: string]
proc initLevel(node: JsonNode): Level = (node: node, key: nil) proc initLevel(node: JsonNode): Level = (node: node, key: cast[string](nil))
proc jsonFromScalar(content: string, typeHint: YamlTypeHint): JsonNode = proc jsonFromScalar(content: string, typeHint: YamlTypeHint): JsonNode =
new(result) new(result)
@ -36,6 +36,7 @@ proc parseToJson*(s: Stream): seq[JsonNode] =
tagInt = parser.registerUri("tag:yaml.org,2002:int") tagInt = parser.registerUri("tag:yaml.org,2002:int")
tagFloat = parser.registerUri("tag:yaml.org,2002:float") tagFloat = parser.registerUri("tag:yaml.org,2002:float")
events = parser.parse(s) events = parser.parse(s)
anchors = initTable[AnchorId, JsonNode]()
for event in events(): for event in events():
case event.kind case event.kind
@ -47,23 +48,36 @@ proc parseToJson*(s: Stream): seq[JsonNode] =
# we can savely assume that levels has e length of exactly 1. # we can savely assume that levels has e length of exactly 1.
result.add(levels.pop().node) result.add(levels.pop().node)
of yamlStartSequence: of yamlStartSequence:
levels.add((node: newJArray(), key: cast[string](nil))) levels.add(initLevel(newJArray()))
if event.objAnchor != anchorNone:
anchors[event.objAnchor] = levels[levels.high].node
of yamlStartMap: of yamlStartMap:
levels.add((node: newJObject(), key: cast[string](nil))) levels.add(initLevel(newJObject()))
if event.objAnchor != anchorNone:
anchors[event.objAnchor] = levels[levels.high].node
of yamlScalar: of yamlScalar:
case levels[levels.high].node.kind case levels[levels.high].node.kind
of JArray: of JArray:
levels[levels.high].node.elems.add( let jsonScalar = jsonFromScalar(event.scalarContent,
jsonFromScalar(event.scalarContent, event.scalarType)) event.scalarType)
levels[levels.high].node.elems.add(jsonScalar)
if event.scalarAnchor != anchorNone:
anchors[event.scalarAnchor] = jsonScalar
of JObject: of JObject:
if isNil(levels[levels.high].key): if isNil(levels[levels.high].key):
# JSON only allows strings as keys # JSON only allows strings as keys
levels[levels.high].key = event.scalarContent levels[levels.high].key = event.scalarContent
if event.scalarAnchor != anchorNone:
raise newException(ValueError,
"scalar keys may not have anchors in JSON")
else: else:
let jsonScalar = jsonFromScalar(event.scalarContent,
event.scalarType)
levels[levels.high].node.fields.add( levels[levels.high].node.fields.add(
(key: levels[levels.high].key, val: jsonFromScalar( (key: levels[levels.high].key, val: jsonScalar))
event.scalarContent, event.scalarType)))
levels[levels.high].key = nil levels[levels.high].key = nil
if event.scalarAnchor != anchorNone:
anchors[event.scalarAnchor] = jsonScalar
else: else:
discard # will never happen discard # will never happen
of yamlEndSequence, yamlEndMap: of yamlEndSequence, yamlEndMap:
@ -91,4 +105,19 @@ proc parseToJson*(s: Stream): seq[JsonNode] =
echo "YAML error at line ", event.line, ", column ", event.column, echo "YAML error at line ", event.line, ", column ", event.column,
": ", event.description ": ", event.description
of yamlAlias: of yamlAlias:
discard # todo # we can savely assume that the alias exists in anchors
# (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])
of JObject:
if isNil(levels[levels.high].key):
raise newException(ValueError,
"cannot use alias node as key in JSON")
else:
levels[levels.high].node.fields.add(
(key: levels[levels.high].key,
val: anchors[event.aliasTarget]))
levels[levels.high].key = nil
else:
discard # will never happen

View File

@ -25,36 +25,6 @@ type
BlockScalarStyle = enum BlockScalarStyle = enum
bsLiteral, bsFolded bsLiteral, bsFolded
const
tagExclamationMark*: TagId = 0.TagId # "!" non-specific tag
tagQuestionMark* : TagId = 1.TagId # "?" non-specific tag
anchorNone*: AnchorId = (-1).AnchorId # no anchor defined
# interface
proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool
proc `==`*(left, right: TagId): bool {.borrow.}
proc `$`*(id: TagId): string {.borrow.}
proc `==`*(left, right: AnchorId): bool {.borrow.}
proc `$`*(id: AnchorId): string {.borrow.}
proc newParser*(): YamlSequentialParser
# iterators cannot be pre-declared.
#
# iterator events*(parser: YamlSequentialParser,
# input: Stream): YamlParserEvent
proc uri*(parser: YamlSequentialParser, id: TagId): string
proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId
proc anchor*(parser: YamlSequentialParser, id: AnchorId): string
# implementation
proc newParser*(): YamlSequentialParser = proc newParser*(): YamlSequentialParser =
new(result) new(result)
result.tags = initOrderedTable[string, TagId]() result.tags = initOrderedTable[string, TagId]()

View File

@ -1,4 +1,4 @@
import streams, unicode, lexbase, tables, strutils, json import streams, unicode, lexbase, tables, strutils, json, hashes
type type
YamlTypeHint* = enum YamlTypeHint* = enum
@ -36,8 +36,31 @@ type
tags: OrderedTable[string, TagId] tags: OrderedTable[string, TagId]
anchors: OrderedTable[string, AnchorId] anchors: OrderedTable[string, AnchorId]
const
tagExclamationMark*: TagId = 0.TagId # "!" non-specific tag
tagQuestionMark* : TagId = 1.TagId # "?" non-specific tag
anchorNone*: AnchorId = (-1).AnchorId # no anchor defined
# interface # interface
proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool
proc `==`*(left, right: TagId): bool {.borrow.}
proc `$`*(id: TagId): string {.borrow.}
proc hash*(id: TagId): Hash {.borrow.}
proc `==`*(left, right: AnchorId): bool {.borrow.}
proc `$`*(id: AnchorId): string {.borrow.}
proc hash*(id: AnchorId): Hash {.borrow.}
proc newParser*(): YamlSequentialParser
proc uri*(parser: YamlSequentialParser, id: TagId): string
proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId
proc anchor*(parser: YamlSequentialParser, id: AnchorId): string
proc parse*(parser: YamlSequentialParser, s: Stream): proc parse*(parser: YamlSequentialParser, s: Stream):
iterator(): YamlParserEvent iterator(): YamlParserEvent

View File

@ -1 +0,0 @@
import lexing, parsing