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