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