source: pyyaml/trunk/lib/yaml/composer.py @ 142

Revision 142, 4.2 KB checked in by xi, 8 years ago (diff)

Add support for recursive nodes to Composer. Constructor does not support recursive objects though.

RevLine 
[53]1
[137]2__all__ = ['Composer', 'ComposerError']
[57]3
[53]4from error import MarkedYAMLError
5from events import *
6from nodes import *
7
8class ComposerError(MarkedYAMLError):
9    pass
10
[137]11class Composer:
[53]12
[136]13    def __init__(self):
[142]14        self.anchors = {}
[53]15
[136]16    def check_node(self):
[53]17        # If there are more documents available?
[136]18        return not self.check_event(StreamEndEvent)
[53]19
[136]20    def get_node(self):
[53]21        # Get the root node of the next document.
[136]22        if not self.check_event(StreamEndEvent):
[53]23            return self.compose_document()
24
25    def __iter__(self):
26        # Iterator protocol.
[136]27        while not self.check_event(StreamEndEvent):
[53]28            yield self.compose_document()
29
30    def compose_document(self):
[118]31
[136]32        # Drop the STREAM-START event.
33        if self.check_event(StreamStartEvent):
34            self.get_event()
35
[118]36        # Drop the DOCUMENT-START event.
[136]37        self.get_event()
[118]38
39        # Compose the root node.
[137]40        node = self.compose_node(None, None)
[118]41
42        # Drop the DOCUMENT-END event.
[136]43        self.get_event()
[118]44
[53]45        self.complete_anchors = {}
46        return node
47
[137]48    def compose_node(self, parent, index):
[136]49        if self.check_event(AliasEvent):
50            event = self.get_event()
[53]51            anchor = event.anchor
[142]52            if anchor not in self.anchors:
[53]53                raise ComposerError(None, None, "found undefined alias %r"
[116]54                        % anchor.encode('utf-8'), event.start_mark)
[142]55            return self.anchors[anchor]
[136]56        event = self.peek_event()
[53]57        anchor = event.anchor
58        if anchor is not None:
[142]59            if anchor in self.anchors:
[53]60                raise ComposerError("found duplicate anchor %r; first occurence"
[142]61                        % anchor.encode('utf-8'), self.anchors[anchor].start_mark,
[116]62                        "second occurence", event.start_mark)
[137]63        self.descend_resolver(parent, index)
[136]64        if self.check_event(ScalarEvent):
[142]65            node = self.compose_scalar_node(anchor)
[136]66        elif self.check_event(SequenceStartEvent):
[142]67            node = self.compose_sequence_node(anchor)
[136]68        elif self.check_event(MappingStartEvent):
[142]69            node = self.compose_mapping_node(anchor)
[137]70        self.ascend_resolver()
[53]71        return node
72
[142]73    def compose_scalar_node(self, anchor):
[136]74        event = self.get_event()
[137]75        tag = event.tag
76        if tag is None or tag == u'!':
77            tag = self.resolve(ScalarNode, event.value, event.implicit)
[142]78        node = ScalarNode(tag, event.value,
[133]79                event.start_mark, event.end_mark, style=event.style)
[142]80        if anchor is not None:
81            self.anchors[anchor] = node
82        return node
[53]83
[142]84    def compose_sequence_node(self, anchor):
[136]85        start_event = self.get_event()
[137]86        tag = start_event.tag
87        if tag is None or tag == u'!':
88            tag = self.resolve(SequenceNode, None, start_event.implicit)
[136]89        node = SequenceNode(tag, [],
90                start_event.start_mark, None,
[133]91                flow_style=start_event.flow_style)
[142]92        if anchor is not None:
93            self.anchors[anchor] = node
[136]94        index = 0
95        while not self.check_event(SequenceEndEvent):
[137]96            node.value.append(self.compose_node(node, index))
[136]97            index += 1
98        end_event = self.get_event()
99        node.end_mark = end_event.end_mark
100        return node
[53]101
[142]102    def compose_mapping_node(self, anchor):
[136]103        start_event = self.get_event()
[137]104        tag = start_event.tag
105        if tag is None or tag == u'!':
106            tag = self.resolve(MappingNode, None, start_event.implicit)
[136]107        node = MappingNode(tag, {},
108                start_event.start_mark, None,
109                flow_style=start_event.flow_style)
[142]110        if anchor is not None:
111            self.anchors[anchor] = node
[136]112        while not self.check_event(MappingEndEvent):
113            key_event = self.peek_event()
[137]114            item_key = self.compose_node(node, None)
[136]115            if item_key in node.value:
[116]116                raise ComposerError("while composing a mapping", start_event.start_mark,
117                        "found duplicate key", key_event.start_mark)
[137]118            item_value = self.compose_node(node, item_key)
[136]119            node.value[item_key] = item_value
120        end_event = self.get_event()
121        node.end_mark = end_event.end_mark
122        return node
[53]123
Note: See TracBrowser for help on using the repository browser.