diff --git a/.gitignore b/.gitignore index 088a244..6ba6cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ nimcache nakefile test/tests -test/tests.exe -test/tests.pdb -test/tests.ilk +test/parsing +test/lexing +test/*.exe +test/*.pdb +test/*.ilk diff --git a/src/private/json.nim b/src/private/json.nim index 4439be6..8940f84 100644 --- a/src/private/json.nim +++ b/src/private/json.nim @@ -1,7 +1,7 @@ type 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 = new(result) @@ -35,7 +35,8 @@ proc parseToJson*(s: Stream): seq[JsonNode] = tagNull = parser.registerUri("tag:yaml.org,2002:null") tagInt = parser.registerUri("tag:yaml.org,2002:int") tagFloat = parser.registerUri("tag:yaml.org,2002:float") - events = parser.parse(s) + events = parser.parse(s) + anchors = initTable[AnchorId, JsonNode]() for event in events(): 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. result.add(levels.pop().node) 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: - 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: case levels[levels.high].node.kind of JArray: - levels[levels.high].node.elems.add( - jsonFromScalar(event.scalarContent, event.scalarType)) + let jsonScalar = jsonFromScalar(event.scalarContent, + event.scalarType) + levels[levels.high].node.elems.add(jsonScalar) + if event.scalarAnchor != anchorNone: + anchors[event.scalarAnchor] = jsonScalar of JObject: if isNil(levels[levels.high].key): # JSON only allows strings as keys levels[levels.high].key = event.scalarContent + if event.scalarAnchor != anchorNone: + raise newException(ValueError, + "scalar keys may not have anchors in JSON") else: + let jsonScalar = jsonFromScalar(event.scalarContent, + event.scalarType) levels[levels.high].node.fields.add( - (key: levels[levels.high].key, val: jsonFromScalar( - event.scalarContent, event.scalarType))) + (key: levels[levels.high].key, val: jsonScalar)) levels[levels.high].key = nil + if event.scalarAnchor != anchorNone: + anchors[event.scalarAnchor] = jsonScalar else: discard # will never happen of yamlEndSequence, yamlEndMap: @@ -91,4 +105,19 @@ proc parseToJson*(s: Stream): seq[JsonNode] = echo "YAML error at line ", event.line, ", column ", event.column, ": ", event.description of yamlAlias: - discard # todo \ No newline at end of file + # 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 \ No newline at end of file diff --git a/src/private/sequential.nim b/src/private/sequential.nim index 03d86a2..412c7cc 100644 --- a/src/private/sequential.nim +++ b/src/private/sequential.nim @@ -25,36 +25,6 @@ type BlockScalarStyle = enum 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 = new(result) result.tags = initOrderedTable[string, TagId]() diff --git a/src/yaml.nim b/src/yaml.nim index 45baeaa..92c8562 100644 --- a/src/yaml.nim +++ b/src/yaml.nim @@ -1,4 +1,4 @@ -import streams, unicode, lexbase, tables, strutils, json +import streams, unicode, lexbase, tables, strutils, json, hashes type YamlTypeHint* = enum @@ -36,8 +36,31 @@ type tags: OrderedTable[string, TagId] 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 +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): iterator(): YamlParserEvent diff --git a/test/tests.nim b/test/tests.nim deleted file mode 100644 index b6c4c6e..0000000 --- a/test/tests.nim +++ /dev/null @@ -1 +0,0 @@ -import lexing, parsing \ No newline at end of file