source: pyyaml/branches/working-on-emitter/lib/yaml/emitter.py @ 129

Revision 129, 13.7 KB checked in by xi, 9 years ago (diff)

Add block styles.

Line 
1
2# Events should obey the following grammar:
3# stream ::= STREAM-START document* STREAM-END
4# document ::= DOCUMENT-START node DOCUMENT-END
5# node ::= SCALAR | sequence | mapping
6# sequence ::= SEQUENCE-START node* SEQUENCE-END
7# mapping ::= MAPPING-START (node node)* MAPPING-END
8
9__all__ = ['Emitter', 'EmitterError']
10
11from error import YAMLError
12from events import *
13
14class EmitterError(YAMLError):
15    pass
16
17class Emitter:
18
19    def __init__(self, writer):
20        self.writer = writer
21        self.states = []
22        self.state = self.expect_stream_start
23        self.indents = []
24        self.indent = None
25        self.flow_level = 0
26        self.key_context = False
27        self.space = True
28        self.line = True
29        self.allow_inline_collection = False
30        self.allow_indentless_sequence = False
31        self.simple_key = False
32        self.event_queue = []
33
34    def emit(self, event):
35        if self.event_queue:
36            self.event_queue.append(event)
37            event = self.event_queue.pop(0)
38        self.state(event)
39
40    def push_back(self, event):
41        self.event_queue.insert(0, event)
42
43    def expect_stream_start(self, event):
44        if isinstance(event, StreamStartEvent):
45            self.state = self.expect_document_start
46        else:
47            raise EmitterError("expected StreamStartEvent, but got %s" % event.__class__.__name__)
48
49    def expect_document_start(self, event):
50        if isinstance(event, DocumentStartEvent):
51            self.write_document_start()
52            self.states.append(self.expect_document_end)
53            self.state = self.expect_root_node
54            self.allow_inline_collection = False
55            self.allow_indentless_sequence = False
56        elif isinstance(event, StreamEndEvent):
57            self.writer.flush()
58            self.state = self.expect_nothing
59        else:
60            raise EmitterError("expected DocumentStartEvent, but got %s" % event.__class__.__name__)
61
62    def expect_document_end(self, event):
63        if isinstance(event, DocumentEndEvent):
64            self.write_document_end()
65            self.state = self.expect_document_start
66            self.allow_inline_collection = False
67            self.allow_indentless_sequence = False
68        else:
69            raiseEmitterError("expected DocumentEndEvent, but got %s" % event.__class__.__name__)
70
71    def expect_root_node(self, event):
72        self.expect_node(event)
73
74    def expect_node(self, event):
75        empty = None
76        if isinstance(event, (SequenceEvent, MappingEvent)):
77            if not self.event_queue:
78                return self.push_back(event)
79            empty = isinstance(self.event_queue[0], CollectionEndEvent)
80        if isinstance(event, AliasEvent):
81            self.expect_alias(event)
82        elif isinstance(event, (ScalarEvent, SequenceEvent, MappingEvent)):
83            if event.anchor:
84                self.write_anchor("&", event.anchor)
85                self.allow_inline_collection = False
86            if event.tag not in [None, u'!']:
87                self.write_tag(event.tag)
88                self.allow_inline_collection = False
89            if isinstance(event, ScalarEvent):
90                self.expect_scalar(event)
91            elif isinstance(event, SequenceEvent):
92                self.expect_sequence(event, empty)
93            elif isinstance(event, MappingEvent):
94                self.expect_mapping(event, empty)
95        else:
96            raise EmitterError("Expected NodeEvent, but got %s" % event.__class__.__name__)
97
98    def expect_alias(self, event):
99        self.write_anchor("*", event.anchor)
100        self.state = self.states.pop()
101
102    def expect_scalar(self, event):
103        self.indents.append(self.indent)
104        if self.indent is None:
105            self.indent = 2
106        else:
107            self.indent += 2
108        self.write_scalar(event.value, event.implicit, event.style)
109        self.indent = self.indents.pop()
110        self.state = self.states.pop()
111        self.allow_inline_collection = False
112        self.allow_indentless_sequence = False
113
114    def expect_sequence(self, event, empty):
115        if self.flow_level or event.flow or empty:
116            self.write_indicator("[", need_space=True, provide_space=True)
117            self.flow_level += 1
118            self.indents.append(self.indent)
119            if self.indent is None:
120                self.indent = 2
121            else:
122                self.indent += 2
123            self.state = self.expect_first_flow_sequence_item
124        else:
125            self.indents.append(self.indent)
126            if self.indent is None:
127                self.indent = 0
128            else:
129                self.indent += 2
130            self.state = self.expect_first_block_sequence_item
131
132    def expect_mapping(self, event, empty):
133        if self.flow_level or event.flow or empty:
134            self.write_indicator("{", need_space=True, provide_space=True)
135            self.flow_level += 1
136            self.indents.append(self.indent)
137            if self.indent is None:
138                self.indent = 2
139            else:
140                self.indent += 2
141            self.state = self.expect_first_flow_mapping_key
142        else:
143            self.indents.append(self.indent)
144            if self.indent is None:
145                self.indent = 0
146            else:
147                self.indent += 2
148            self.state = self.expect_first_block_mapping_key
149
150    def expect_first_flow_sequence_item(self, event):
151        if isinstance(event, CollectionEndEvent):
152            self.indent = self.indents.pop()
153            self.write_indicator("]", provide_space=True)
154            self.flow_level -= 1
155            self.state = self.states.pop()
156        else:
157            self.write_indent()
158            self.states.append(self.expect_flow_sequence_item)
159            self.state = self.expect_node
160            self.expect_node(event)
161
162    def expect_flow_sequence_item(self, event):
163        if isinstance(event, CollectionEndEvent):
164            self.write_indicator(",")
165            self.indent = self.indents.pop()
166            self.write_indent()
167            self.write_indicator("]")
168            self.flow_level -= 1
169            self.state = self.states.pop()
170        else:
171            self.write_indicator(",")
172            self.write_indent()
173            self.states.append(self.expect_flow_sequence_item)
174            self.state = self.expect_node
175            self.expect_node(event)
176
177    def expect_first_block_sequence_item(self, event):
178        assert not isinstance(event, CollectionEndEvent)
179        if not self.allow_inline_collection:
180            if self.allow_indentless_sequence:
181                self.indent = self.indents.pop()
182                self.indents.append(self.indent)
183            self.write_indent()
184        self.write_indicator("-", need_space=True)
185        self.allow_indentless_sequence = False
186        self.allow_inline_collection = True
187        self.states.append(self.expect_block_sequence_item)
188        self.state = self.expect_node
189        self.expect_node(event)
190
191    def expect_block_sequence_item(self, event):
192        if isinstance(event, CollectionEndEvent):
193            self.indent = self.indents.pop()
194            self.state = self.states.pop()
195        else:
196            self.write_indent()
197            self.write_indicator("-", need_space=True)
198            self.allow_indentless_sequence = False
199            self.allow_inline_collection = True
200            self.states.append(self.expect_block_sequence_item)
201            self.state = self.expect_node
202            self.expect_node(event)
203
204    def expect_first_flow_mapping_key(self, event):
205        if isinstance(event, CollectionEndEvent):
206            self.indent = self.indents.pop()
207            self.write_indicator("}")
208            self.flow_level -= 1
209            self.state = self.states.pop()
210        else:
211            self.write_indent()
212            if self.is_simple(event):
213                self.simple_key = True
214            else:
215                self.write_indicator("?", need_space=True)
216            self.states.append(self.expect_flow_mapping_value)
217            self.state = self.expect_node
218            self.expect_node(event)
219
220    def expect_flow_mapping_key(self, event):
221        if isinstance(event, CollectionEndEvent):
222            self.indent = self.indents.pop()
223            self.write_indent()
224            self.write_indicator("}")
225            self.flow_level -= 1
226            self.state = self.states.pop()
227        else:
228            self.write_indicator(",")
229            self.write_indent()
230            if self.is_simple(event):
231                self.simple_key = True
232            else:
233                self.write_indicator("?", need_space=True)
234            self.states.append(self.expect_flow_mapping_value)
235            self.state = self.expect_node
236            self.expect_node(event)
237
238    def expect_flow_mapping_value(self, event):
239        if self.simple_key:
240            self.write_indicator(":", need_space=False)
241            self.simple_key = False
242        else:
243            self.write_indent()
244            self.write_indicator(":", need_space=True)
245        self.states.append(self.expect_flow_mapping_key)
246        self.state = self.expect_node
247        self.expect_node(event)
248
249    def expect_first_block_mapping_key(self, event):
250        assert not isinstance(event, CollectionEndEvent)
251        simple = self.is_simple(event)
252        if simple is None:
253            return self.push_back(event)
254        if not self.allow_inline_collection:
255            self.write_indent()
256        if self.is_simple(event):
257            self.allow_indentless_sequence = True
258            self.allow_inline_collection = False
259            self.simple_key = True
260        else:
261            self.write_indicator("?", need_space=True)
262            self.allow_indentless_sequence = True
263            self.allow_inline_collection = True
264        self.states.append(self.expect_block_mapping_value)
265        self.state = self.expect_node
266        self.expect_node(event)
267
268    def expect_block_mapping_key(self, event):
269        if isinstance(event, CollectionEndEvent):
270            self.indent = self.indents.pop()
271            self.state = self.states.pop()
272        else:
273            self.write_indent()
274            if self.is_simple(event):
275                self.allow_indentless_sequence = True
276                self.allow_inline_collection = False
277                self.simple_key = True
278            else:
279                self.write_indicator("?", need_space=True)
280                self.allow_indentless_sequence = True
281                self.allow_inline_collection = True
282            self.states.append(self.expect_block_mapping_value)
283            self.state = self.expect_node
284            self.expect_node(event)
285
286    def expect_block_mapping_value(self, event):
287        if self.simple_key:
288            self.write_indicator(":", need_space=False)
289            self.allow_indentless_sequence = True
290            self.allow_inline_collection = False
291            self.simple_key = False
292        else:
293            self.write_indent()
294            self.write_indicator(":", need_space=True)
295            self.allow_indentless_sequence = True
296            self.allow_inline_collection = True
297        self.states.append(self.expect_block_mapping_key)
298        self.state = self.expect_node
299        self.expect_node(event)
300
301    def expect_nothing(self, event):
302        raise EmitterError("expected nothing, but got %s" % event.__class__.__name__)
303
304    def write_document_start(self):
305        self.writer.write("%YAML 1.1")
306        self.write_line_break()
307        self.writer.write("---")
308        self.space = False
309        self.line = False
310
311    def write_document_end(self):
312        if not self.line:
313            self.write_line_break()
314        self.writer.write("...")
315        self.write_line_break()
316
317    def write_line_break(self):
318        self.writer.write('\n')
319        self.space = True
320        self.line = True
321
322    def write_anchor(self, indicator, name):
323        if not self.space:
324            self.writer.write(" ")
325        self.writer.write("%s%s" % (indicator, name))
326        self.space = False
327        self.line = False
328
329    def write_tag(self, tag):
330        if not self.space:
331            self.writer.write(" ")
332        if tag.startswith("tag:yaml.org,2002:"):
333            self.writer.write("!!%s" % tag[len("tag.yaml.org,2002:"):])
334        else:
335            self.writer.write("!<%s>" % tag)
336        self.space = False
337        self.line = False
338
339    def is_simple(self, event):
340        if not isinstance(event, ScalarEvent):
341            return False
342        if '\n' in event.value or len(event.value) > 128:
343            return False
344        if event.style and event.style in '|>':
345            return False
346        return True
347
348    def write_scalar(self, value, implicit, style):
349        if implicit:
350            if not self.space:
351                self.writer.write(" ")
352            self.writer.write(value.encode('utf-8'))
353            self.space = False
354            self.line = False
355        elif style in ['>', '|'] and not self.flow_level and not self.simple_key:
356            if not self.space:
357                self.writer.write(" ")
358            self.writer.write("|-")
359            self.write_line_break()
360            self.write_indent()
361            self.writer.write(value.encode('utf-8'))
362            self.write_line_break()
363        else:
364            if not self.space:
365                self.writer.write(" ")
366            self.writer.write("\"%s\"" % value.encode('utf-8'))
367            self.space = False
368            self.line = False
369
370    def write_indicator(self, indicator, need_space=False, provide_space=False):
371        if need_space and not self.space:
372            self.writer.write(" ")
373        self.writer.write(indicator)
374        self.space = provide_space
375        self.line = False
376
377    def write_indent(self):
378        if not self.line:
379            self.write_line_break()
380        if self.indent:
381            self.writer.write(" "*self.indent)
382            self.line = False
383        self.space = True
384
Note: See TracBrowser for help on using the repository browser.