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