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

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

Add block styles.

RevLine 
[122]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
[129]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 = []
[122]33
34    def emit(self, event):
[129]35        if self.event_queue:
36            self.event_queue.append(event)
37            event = self.event_queue.pop(0)
[122]38        self.state(event)
39
[129]40    def push_back(self, event):
41        self.event_queue.insert(0, event)
42
[122]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
[129]54            self.allow_inline_collection = False
55            self.allow_indentless_sequence = False
[122]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
[129]66            self.allow_inline_collection = False
67            self.allow_indentless_sequence = False
[122]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):
[129]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)
[122]80        if isinstance(event, AliasEvent):
[129]81            self.expect_alias(event)
82        elif isinstance(event, (ScalarEvent, SequenceEvent, MappingEvent)):
[122]83            if event.anchor:
84                self.write_anchor("&", event.anchor)
[129]85                self.allow_inline_collection = False
86            if event.tag not in [None, u'!']:
[122]87                self.write_tag(event.tag)
[129]88                self.allow_inline_collection = False
[122]89            if isinstance(event, ScalarEvent):
[129]90                self.expect_scalar(event)
[122]91            elif isinstance(event, SequenceEvent):
[129]92                self.expect_sequence(event, empty)
[122]93            elif isinstance(event, MappingEvent):
[129]94                self.expect_mapping(event, empty)
[122]95        else:
96            raise EmitterError("Expected NodeEvent, but got %s" % event.__class__.__name__)
97
[129]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):
[122]151        if isinstance(event, CollectionEndEvent):
[129]152            self.indent = self.indents.pop()
153            self.write_indicator("]", provide_space=True)
154            self.flow_level -= 1
[122]155            self.state = self.states.pop()
156        else:
157            self.write_indent()
[129]158            self.states.append(self.expect_flow_sequence_item)
159            self.state = self.expect_node
[122]160            self.expect_node(event)
161
[129]162    def expect_flow_sequence_item(self, event):
[122]163        if isinstance(event, CollectionEndEvent):
[129]164            self.write_indicator(",")
165            self.indent = self.indents.pop()
[122]166            self.write_indent()
[129]167            self.write_indicator("]")
168            self.flow_level -= 1
[122]169            self.state = self.states.pop()
170        else:
171            self.write_indicator(",")
172            self.write_indent()
[129]173            self.states.append(self.expect_flow_sequence_item)
174            self.state = self.expect_node
[122]175            self.expect_node(event)
[129]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):
[122]192        if isinstance(event, CollectionEndEvent):
[129]193            self.indent = self.indents.pop()
[122]194            self.state = self.states.pop()
195        else:
196            self.write_indent()
[129]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
[122]202            self.expect_node(event)
203
[129]204    def expect_first_flow_mapping_key(self, event):
[122]205        if isinstance(event, CollectionEndEvent):
[129]206            self.indent = self.indents.pop()
207            self.write_indicator("}")
208            self.flow_level -= 1
209            self.state = self.states.pop()
210        else:
[122]211            self.write_indent()
[129]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
[122]226            self.state = self.states.pop()
227        else:
228            self.write_indicator(",")
229            self.write_indent()
[129]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
[122]236            self.expect_node(event)
237
[129]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
[122]247        self.expect_node(event)
248
[129]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
[122]301    def expect_nothing(self, event):
302        raise EmitterError("expected nothing, but got %s" % event.__class__.__name__)
303
304    def write_document_start(self):
[129]305        self.writer.write("%YAML 1.1")
306        self.write_line_break()
[122]307        self.writer.write("---")
[129]308        self.space = False
309        self.line = False
[122]310
311    def write_document_end(self):
[129]312        if not self.line:
313            self.write_line_break()
314        self.writer.write("...")
315        self.write_line_break()
[122]316
[129]317    def write_line_break(self):
318        self.writer.write('\n')
319        self.space = True
320        self.line = True
[122]321
322    def write_anchor(self, indicator, name):
[129]323        if not self.space:
[122]324            self.writer.write(" ")
325        self.writer.write("%s%s" % (indicator, name))
[129]326        self.space = False
327        self.line = False
[122]328
329    def write_tag(self, tag):
[129]330        if not self.space:
[122]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)
[129]336        self.space = False
337        self.line = False
[122]338
[129]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:
[122]372            self.writer.write(" ")
373        self.writer.write(indicator)
[129]374        self.space = provide_space
375        self.line = False
[122]376
377    def write_indent(self):
[129]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
[122]384
Note: See TracBrowser for help on using the repository browser.