source: pyyaml/trunk/ext/_yaml.pyx @ 333

Revision 333, 58.5 KB checked in by xi, 6 years ago (diff)

Handle the encoding of input and output streams in a uniform way.

Line 
1
2import yaml
3
4def get_version_string():
5    return yaml_get_version_string()
6
7def get_version():
8    cdef int major, minor, patch
9    yaml_get_version(&major, &minor, &patch)
10    return (major, minor, patch)
11
12#Mark = yaml.error.Mark
13YAMLError = yaml.error.YAMLError
14ReaderError = yaml.reader.ReaderError
15ScannerError = yaml.scanner.ScannerError
16ParserError = yaml.parser.ParserError
17ComposerError = yaml.composer.ComposerError
18ConstructorError = yaml.constructor.ConstructorError
19EmitterError = yaml.emitter.EmitterError
20SerializerError = yaml.serializer.SerializerError
21RepresenterError = yaml.representer.RepresenterError
22
23StreamStartToken = yaml.tokens.StreamStartToken
24StreamEndToken = yaml.tokens.StreamEndToken
25DirectiveToken = yaml.tokens.DirectiveToken
26DocumentStartToken = yaml.tokens.DocumentStartToken
27DocumentEndToken = yaml.tokens.DocumentEndToken
28BlockSequenceStartToken = yaml.tokens.BlockSequenceStartToken
29BlockMappingStartToken = yaml.tokens.BlockMappingStartToken
30BlockEndToken = yaml.tokens.BlockEndToken
31FlowSequenceStartToken = yaml.tokens.FlowSequenceStartToken
32FlowMappingStartToken = yaml.tokens.FlowMappingStartToken
33FlowSequenceEndToken = yaml.tokens.FlowSequenceEndToken
34FlowMappingEndToken = yaml.tokens.FlowMappingEndToken
35KeyToken = yaml.tokens.KeyToken
36ValueToken = yaml.tokens.ValueToken
37BlockEntryToken = yaml.tokens.BlockEntryToken
38FlowEntryToken = yaml.tokens.FlowEntryToken
39AliasToken = yaml.tokens.AliasToken
40AnchorToken = yaml.tokens.AnchorToken
41TagToken = yaml.tokens.TagToken
42ScalarToken = yaml.tokens.ScalarToken
43
44StreamStartEvent = yaml.events.StreamStartEvent
45StreamEndEvent = yaml.events.StreamEndEvent
46DocumentStartEvent = yaml.events.DocumentStartEvent
47DocumentEndEvent = yaml.events.DocumentEndEvent
48AliasEvent = yaml.events.AliasEvent
49ScalarEvent = yaml.events.ScalarEvent
50SequenceStartEvent = yaml.events.SequenceStartEvent
51SequenceEndEvent = yaml.events.SequenceEndEvent
52MappingStartEvent = yaml.events.MappingStartEvent
53MappingEndEvent = yaml.events.MappingEndEvent
54
55ScalarNode = yaml.nodes.ScalarNode
56SequenceNode = yaml.nodes.SequenceNode
57MappingNode = yaml.nodes.MappingNode
58
59cdef class Mark:
60    cdef readonly object name
61    cdef readonly int index
62    cdef readonly int line
63    cdef readonly int column
64    cdef readonly buffer
65    cdef readonly pointer
66
67    def __init__(self, object name, int index, int line, int column,
68            object buffer, object pointer):
69        self.name = name
70        self.index = index
71        self.line = line
72        self.column = column
73        self.buffer = buffer
74        self.pointer = pointer
75
76    def get_snippet(self):
77        return None
78
79    def __str__(self):
80        where = "  in \"%s\", line %d, column %d"   \
81                % (self.name, self.line+1, self.column+1)
82        return where
83
84#class YAMLError(Exception):
85#    pass
86#
87#class MarkedYAMLError(YAMLError):
88#
89#    def __init__(self, context=None, context_mark=None,
90#            problem=None, problem_mark=None, note=None):
91#        self.context = context
92#        self.context_mark = context_mark
93#        self.problem = problem
94#        self.problem_mark = problem_mark
95#        self.note = note
96#
97#    def __str__(self):
98#        lines = []
99#        if self.context is not None:
100#            lines.append(self.context)
101#        if self.context_mark is not None  \
102#            and (self.problem is None or self.problem_mark is None
103#                    or self.context_mark.name != self.problem_mark.name
104#                    or self.context_mark.line != self.problem_mark.line
105#                    or self.context_mark.column != self.problem_mark.column):
106#            lines.append(str(self.context_mark))
107#        if self.problem is not None:
108#            lines.append(self.problem)
109#        if self.problem_mark is not None:
110#            lines.append(str(self.problem_mark))
111#        if self.note is not None:
112#            lines.append(self.note)
113#        return '\n'.join(lines)
114#
115#class ReaderError(YAMLError):
116#
117#    def __init__(self, name, position, character, encoding, reason):
118#        self.name = name
119#        self.character = character
120#        self.position = position
121#        self.encoding = encoding
122#        self.reason = reason
123#
124#    def __str__(self):
125#        if isinstance(self.character, str):
126#            return "'%s' codec can't decode byte #x%02x: %s\n"  \
127#                    "  in \"%s\", position %d"    \
128#                    % (self.encoding, ord(self.character), self.reason,
129#                            self.name, self.position)
130#        else:
131#            return "unacceptable character #x%04x: %s\n"    \
132#                    "  in \"%s\", position %d"    \
133#                    % (ord(self.character), self.reason,
134#                            self.name, self.position)
135#
136#class ScannerError(MarkedYAMLError):
137#    pass
138#
139#class ParserError(MarkedYAMLError):
140#    pass
141#
142#class EmitterError(YAMLError):
143#    pass
144#
145#cdef class Token:
146#    cdef readonly Mark start_mark
147#    cdef readonly Mark end_mark
148#    def __init__(self, Mark start_mark, Mark end_mark):
149#        self.start_mark = start_mark
150#        self.end_mark = end_mark
151#
152#cdef class StreamStartToken(Token):
153#    cdef readonly object encoding
154#    def __init__(self, Mark start_mark, Mark end_mark, encoding):
155#        self.start_mark = start_mark
156#        self.end_mark = end_mark
157#        self.encoding = encoding
158#
159#cdef class StreamEndToken(Token):
160#    pass
161#
162#cdef class DirectiveToken(Token):
163#    cdef readonly object name
164#    cdef readonly object value
165#    def __init__(self, name, value, Mark start_mark, Mark end_mark):
166#        self.name = name
167#        self.value = value
168#        self.start_mark = start_mark
169#        self.end_mark = end_mark
170#
171#cdef class DocumentStartToken(Token):
172#    pass
173#
174#cdef class DocumentEndToken(Token):
175#    pass
176#
177#cdef class BlockSequenceStartToken(Token):
178#    pass
179#
180#cdef class BlockMappingStartToken(Token):
181#    pass
182#
183#cdef class BlockEndToken(Token):
184#    pass
185#
186#cdef class FlowSequenceStartToken(Token):
187#    pass
188#
189#cdef class FlowMappingStartToken(Token):
190#    pass
191#
192#cdef class FlowSequenceEndToken(Token):
193#    pass
194#
195#cdef class FlowMappingEndToken(Token):
196#    pass
197#
198#cdef class KeyToken(Token):
199#    pass
200#
201#cdef class ValueToken(Token):
202#    pass
203#
204#cdef class BlockEntryToken(Token):
205#    pass
206#
207#cdef class FlowEntryToken(Token):
208#    pass
209#
210#cdef class AliasToken(Token):
211#    cdef readonly object value
212#    def __init__(self, value, Mark start_mark, Mark end_mark):
213#        self.value = value
214#        self.start_mark = start_mark
215#        self.end_mark = end_mark
216#
217#cdef class AnchorToken(Token):
218#    cdef readonly object value
219#    def __init__(self, value, Mark start_mark, Mark end_mark):
220#        self.value = value
221#        self.start_mark = start_mark
222#        self.end_mark = end_mark
223#
224#cdef class TagToken(Token):
225#    cdef readonly object value
226#    def __init__(self, value, Mark start_mark, Mark end_mark):
227#        self.value = value
228#        self.start_mark = start_mark
229#        self.end_mark = end_mark
230#
231#cdef class ScalarToken(Token):
232#    cdef readonly object value
233#    cdef readonly object plain
234#    cdef readonly object style
235#    def __init__(self, value, plain, Mark start_mark, Mark end_mark, style=None):
236#        self.value = value
237#        self.plain = plain
238#        self.start_mark = start_mark
239#        self.end_mark = end_mark
240#        self.style = style
241
242cdef class CParser:
243
244    cdef yaml_parser_t parser
245    cdef yaml_event_t parsed_event
246
247    cdef object stream
248    cdef object stream_name
249    cdef object current_token
250    cdef object current_event
251    cdef object anchors
252    cdef object stream_cache
253    cdef int stream_cache_len
254    cdef int stream_cache_pos
255    cdef int unicode_source
256
257    def __init__(self, stream):
258        cdef is_readable
259        if yaml_parser_initialize(&self.parser) == 0:
260            raise MemoryError
261        self.parsed_event.type = YAML_NO_EVENT
262        is_readable = 1
263        try:
264            stream.read
265        except AttributeError:
266            is_readable = 0
267        self.unicode_source = 0
268        if is_readable:
269            self.stream = stream
270            try:
271                self.stream_name = stream.name
272            except AttributeError:
273                self.stream_name = '<file>'
274            self.stream_cache = None
275            self.stream_cache_len = 0
276            self.stream_cache_pos = 0
277            yaml_parser_set_input(&self.parser, input_handler, <void *>self)
278        else:
279            if PyUnicode_CheckExact(stream) != 0:
280                stream = PyUnicode_AsUTF8String(stream)
281                self.stream_name = '<unicode string>'
282                self.unicode_source = 1
283            else:
284                self.stream_name = '<byte string>'
285            if PyString_CheckExact(stream) == 0:
286                raise TypeError("a string or stream input is required")
287            self.stream = stream
288            yaml_parser_set_input_string(&self.parser, PyString_AS_STRING(stream), PyString_GET_SIZE(stream))
289        self.current_token = None
290        self.current_event = None
291        self.anchors = {}
292
293    def __dealloc__(self):
294        yaml_parser_delete(&self.parser)
295        yaml_event_delete(&self.parsed_event)
296
297    cdef object _parser_error(self):
298        if self.parser.error == YAML_MEMORY_ERROR:
299            return MemoryError
300        elif self.parser.error == YAML_READER_ERROR:
301            return ReaderError(self.stream_name, self.parser.problem_offset,
302                    self.parser.problem_value, '?', self.parser.problem)
303        elif self.parser.error == YAML_SCANNER_ERROR    \
304                or self.parser.error == YAML_PARSER_ERROR:
305            context_mark = None
306            problem_mark = None
307            if self.parser.context != NULL:
308                context_mark = Mark(self.stream_name,
309                        self.parser.context_mark.index,
310                        self.parser.context_mark.line,
311                        self.parser.context_mark.column, None, None)
312            if self.parser.problem != NULL:
313                problem_mark = Mark(self.stream_name,
314                        self.parser.problem_mark.index,
315                        self.parser.problem_mark.line,
316                        self.parser.problem_mark.column, None, None)
317            if self.parser.error == YAML_SCANNER_ERROR:
318                if self.parser.context != NULL:
319                    return ScannerError(self.parser.context, context_mark,
320                            self.parser.problem, problem_mark)
321                else:
322                    return ScannerError(None, None,
323                            self.parser.problem, problem_mark)
324            else:
325                if self.parser.context != NULL:
326                    return ParserError(self.parser.context, context_mark,
327                            self.parser.problem, problem_mark)
328                else:
329                    return ParserError(None, None,
330                            self.parser.problem, problem_mark)
331        raise ValueError("no parser error")
332
333    def raw_scan(self):
334        cdef yaml_token_t token
335        cdef int done
336        cdef int count
337        count = 0
338        done = 0
339        while done == 0:
340            if yaml_parser_scan(&self.parser, &token) == 0:
341                error = self._parser_error()
342                raise error
343            if token.type == YAML_NO_TOKEN:
344                done = 1
345            else:
346                count = count+1
347            yaml_token_delete(&token)
348        return count
349
350    cdef object _scan(self):
351        cdef yaml_token_t token
352        if yaml_parser_scan(&self.parser, &token) == 0:
353            error = self._parser_error()
354            raise error
355        token_object = self._token_to_object(&token)
356        yaml_token_delete(&token)
357        return token_object
358
359    cdef object _token_to_object(self, yaml_token_t *token):
360        start_mark = Mark(self.stream_name,
361                token.start_mark.index,
362                token.start_mark.line,
363                token.start_mark.column,
364                None, None)
365        end_mark = Mark(self.stream_name,
366                token.end_mark.index,
367                token.end_mark.line,
368                token.end_mark.column,
369                None, None)
370        if token.type == YAML_NO_TOKEN:
371            return None
372        elif token.type == YAML_STREAM_START_TOKEN:
373            encoding = None
374            if token.data.stream_start.encoding == YAML_UTF8_ENCODING:
375                if self.unicode_source == 0:
376                    encoding = u"utf-8"
377            elif token.data.stream_start.encoding == YAML_UTF16LE_ENCODING:
378                encoding = u"utf-16-le"
379            elif token.data.stream_start.encoding == YAML_UTF16BE_ENCODING:
380                encoding = u"utf-16-be"
381            return StreamStartToken(start_mark, end_mark, encoding)
382        elif token.type == YAML_STREAM_END_TOKEN:
383            return StreamEndToken(start_mark, end_mark)
384        elif token.type == YAML_VERSION_DIRECTIVE_TOKEN:
385            return DirectiveToken(u"YAML",
386                    (token.data.version_directive.major,
387                        token.data.version_directive.minor),
388                    start_mark, end_mark)
389        elif token.type == YAML_TAG_DIRECTIVE_TOKEN:
390            handle = PyUnicode_DecodeUTF8(token.data.tag_directive.handle,
391                    strlen(token.data.tag_directive.handle), 'strict')
392            prefix = PyUnicode_DecodeUTF8(token.data.tag_directive.prefix,
393                    strlen(token.data.tag_directive.prefix), 'strict')
394            return DirectiveToken(u"TAG", (handle, prefix),
395                    start_mark, end_mark)
396        elif token.type == YAML_DOCUMENT_START_TOKEN:
397            return DocumentStartToken(start_mark, end_mark)
398        elif token.type == YAML_DOCUMENT_END_TOKEN:
399            return DocumentEndToken(start_mark, end_mark)
400        elif token.type == YAML_BLOCK_SEQUENCE_START_TOKEN:
401            return BlockSequenceStartToken(start_mark, end_mark)
402        elif token.type == YAML_BLOCK_MAPPING_START_TOKEN:
403            return BlockMappingStartToken(start_mark, end_mark)
404        elif token.type == YAML_BLOCK_END_TOKEN:
405            return BlockEndToken(start_mark, end_mark)
406        elif token.type == YAML_FLOW_SEQUENCE_START_TOKEN:
407            return FlowSequenceStartToken(start_mark, end_mark)
408        elif token.type == YAML_FLOW_SEQUENCE_END_TOKEN:
409            return FlowSequenceEndToken(start_mark, end_mark)
410        elif token.type == YAML_FLOW_MAPPING_START_TOKEN:
411            return FlowMappingStartToken(start_mark, end_mark)
412        elif token.type == YAML_FLOW_MAPPING_END_TOKEN:
413            return FlowMappingEndToken(start_mark, end_mark)
414        elif token.type == YAML_BLOCK_ENTRY_TOKEN:
415            return BlockEntryToken(start_mark, end_mark)
416        elif token.type == YAML_FLOW_ENTRY_TOKEN:
417            return FlowEntryToken(start_mark, end_mark)
418        elif token.type == YAML_KEY_TOKEN:
419            return KeyToken(start_mark, end_mark)
420        elif token.type == YAML_VALUE_TOKEN:
421            return ValueToken(start_mark, end_mark)
422        elif token.type == YAML_ALIAS_TOKEN:
423            value = PyUnicode_DecodeUTF8(token.data.alias.value,
424                    strlen(token.data.alias.value), 'strict')
425            return AliasToken(value, start_mark, end_mark)
426        elif token.type == YAML_ANCHOR_TOKEN:
427            value = PyUnicode_DecodeUTF8(token.data.anchor.value,
428                    strlen(token.data.anchor.value), 'strict')
429            return AnchorToken(value, start_mark, end_mark)
430        elif token.type == YAML_TAG_TOKEN:
431            handle = PyUnicode_DecodeUTF8(token.data.tag.handle,
432                    strlen(token.data.tag.handle), 'strict')
433            suffix = PyUnicode_DecodeUTF8(token.data.tag.suffix,
434                    strlen(token.data.tag.suffix), 'strict')
435            if not handle:
436                handle = None
437            return TagToken((handle, suffix), start_mark, end_mark)
438        elif token.type == YAML_SCALAR_TOKEN:
439            value = PyUnicode_DecodeUTF8(token.data.scalar.value,
440                    token.data.scalar.length, 'strict')
441            plain = False
442            style = None
443            if token.data.scalar.style == YAML_PLAIN_SCALAR_STYLE:
444                plain = True
445                style = ''
446            elif token.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE:
447                style = '\''
448            elif token.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE:
449                style = '"'
450            elif token.data.scalar.style == YAML_LITERAL_SCALAR_STYLE:
451                style = '|'
452            elif token.data.scalar.style == YAML_FOLDED_SCALAR_STYLE:
453                style = '>'
454            return ScalarToken(value, plain,
455                    start_mark, end_mark, style)
456        else:
457            raise ValueError("unknown token type")
458
459    def get_token(self):
460        if self.current_token is not None:
461            value = self.current_token
462            self.current_token = None
463        else:
464            value = self._scan()
465        return value
466
467    def peek_token(self):
468        if self.current_token is None:
469            self.current_token = self._scan()
470        return self.current_token
471
472    def check_token(self, *choices):
473        if self.current_token is None:
474            self.current_token = self._scan()
475        if self.current_token is None:
476            return False
477        if not choices:
478            return True
479        token_class = self.current_token.__class__
480        for choice in choices:
481            if token_class is choice:
482                return True
483        return False
484
485    def raw_parse(self):
486        cdef yaml_event_t event
487        cdef int done
488        cdef int count
489        count = 0
490        done = 0
491        while done == 0:
492            if yaml_parser_parse(&self.parser, &event) == 0:
493                error = self._parser_error()
494                raise error
495            if event.type == YAML_NO_EVENT:
496                done = 1
497            else:
498                count = count+1
499            yaml_event_delete(&event)
500        return count
501
502    cdef object _parse(self):
503        cdef yaml_event_t event
504        if yaml_parser_parse(&self.parser, &event) == 0:
505            error = self._parser_error()
506            raise error
507        event_object = self._event_to_object(&event)
508        yaml_event_delete(&event)
509        return event_object
510
511    cdef object _event_to_object(self, yaml_event_t *event):
512        cdef yaml_tag_directive_t *tag_directive
513        start_mark = Mark(self.stream_name,
514                event.start_mark.index,
515                event.start_mark.line,
516                event.start_mark.column,
517                None, None)
518        end_mark = Mark(self.stream_name,
519                event.end_mark.index,
520                event.end_mark.line,
521                event.end_mark.column,
522                None, None)
523        if event.type == YAML_NO_EVENT:
524            return None
525        elif event.type == YAML_STREAM_START_EVENT:
526            encoding = None
527            if event.data.stream_start.encoding == YAML_UTF8_ENCODING:
528                if self.unicode_source == 0:
529                    encoding = "utf-8"
530            elif event.data.stream_start.encoding == YAML_UTF16LE_ENCODING:
531                encoding = "utf-16-le"
532            elif event.data.stream_start.encoding == YAML_UTF16BE_ENCODING:
533                encoding = "utf-16-be"
534            return StreamStartEvent(start_mark, end_mark, encoding)
535        elif event.type == YAML_STREAM_END_EVENT:
536            return StreamEndEvent(start_mark, end_mark)
537
538        elif event.type == YAML_DOCUMENT_START_EVENT:
539            explicit = False
540            if event.data.document_start.implicit == 0:
541                explicit = True
542            version = None
543            if event.data.document_start.version_directive != NULL:
544                version = (event.data.document_start.version_directive.major,
545                        event.data.document_start.version_directive.minor)
546            tags = None
547            if event.data.document_start.tag_directives.start != NULL:
548                tags = {}
549                tag_directive = event.data.document_start.tag_directives.start
550                while tag_directive != event.data.document_start.tag_directives.end:
551                    handle = PyUnicode_DecodeUTF8(tag_directive.handle,
552                            strlen(tag_directive.handle), 'strict')
553                    prefix = PyUnicode_DecodeUTF8(tag_directive.prefix,
554                            strlen(tag_directive.prefix), 'strict')
555                    tags[handle] = prefix
556                    tag_directive = tag_directive+1
557            return DocumentStartEvent(start_mark, end_mark,
558                    explicit, version, tags)
559        elif event.type == YAML_DOCUMENT_END_EVENT:
560            explicit = False
561            if event.data.document_end.implicit == 0:
562                explicit = True
563            return DocumentEndEvent(start_mark, end_mark, explicit)
564        elif event.type == YAML_ALIAS_EVENT:
565            anchor = PyUnicode_DecodeUTF8(event.data.alias.anchor,
566                    strlen(event.data.alias.anchor), 'strict')
567            return AliasEvent(anchor, start_mark, end_mark)
568        elif event.type == YAML_SCALAR_EVENT:
569            anchor = None
570            if event.data.scalar.anchor != NULL:
571                anchor = PyUnicode_DecodeUTF8(event.data.scalar.anchor,
572                        strlen(event.data.scalar.anchor), 'strict')
573            tag = None
574            if event.data.scalar.tag != NULL:
575                tag = PyUnicode_DecodeUTF8(event.data.scalar.tag,
576                        strlen(event.data.scalar.tag), 'strict')
577            value = PyUnicode_DecodeUTF8(event.data.scalar.value,
578                    event.data.scalar.length, 'strict')
579            plain_implicit = False
580            if event.data.scalar.plain_implicit == 1:
581                plain_implicit = True
582            quoted_implicit = False
583            if event.data.scalar.quoted_implicit == 1:
584                quoted_implicit = True
585            style = None
586            if event.data.scalar.style == YAML_PLAIN_SCALAR_STYLE:
587                style = ''
588            elif event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE:
589                style = '\''
590            elif event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE:
591                style = '"'
592            elif event.data.scalar.style == YAML_LITERAL_SCALAR_STYLE:
593                style = '|'
594            elif event.data.scalar.style == YAML_FOLDED_SCALAR_STYLE:
595                style = '>'
596            return ScalarEvent(anchor, tag,
597                    (plain_implicit, quoted_implicit),
598                    value, start_mark, end_mark, style)
599        elif event.type == YAML_SEQUENCE_START_EVENT:
600            anchor = None
601            if event.data.sequence_start.anchor != NULL:
602                anchor = PyUnicode_DecodeUTF8(event.data.sequence_start.anchor,
603                        strlen(event.data.sequence_start.anchor), 'strict')
604            tag = None
605            if event.data.sequence_start.tag != NULL:
606                tag = PyUnicode_DecodeUTF8(event.data.sequence_start.tag,
607                        strlen(event.data.sequence_start.tag), 'strict')
608            implicit = False
609            if event.data.sequence_start.implicit == 1:
610                implicit = True
611            flow_style = None
612            if event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE:
613                flow_style = True
614            elif event.data.sequence_start.style == YAML_BLOCK_SEQUENCE_STYLE:
615                flow_style = False
616            return SequenceStartEvent(anchor, tag, implicit,
617                    start_mark, end_mark, flow_style)
618        elif event.type == YAML_MAPPING_START_EVENT:
619            anchor = None
620            if event.data.mapping_start.anchor != NULL:
621                anchor = PyUnicode_DecodeUTF8(event.data.mapping_start.anchor,
622                        strlen(event.data.mapping_start.anchor), 'strict')
623            tag = None
624            if event.data.mapping_start.tag != NULL:
625                tag = PyUnicode_DecodeUTF8(event.data.mapping_start.tag,
626                        strlen(event.data.mapping_start.tag), 'strict')
627            implicit = False
628            if event.data.mapping_start.implicit == 1:
629                implicit = True
630            flow_style = None
631            if event.data.mapping_start.style == YAML_FLOW_MAPPING_STYLE:
632                flow_style = True
633            elif event.data.mapping_start.style == YAML_BLOCK_MAPPING_STYLE:
634                flow_style = False
635            return MappingStartEvent(anchor, tag, implicit,
636                    start_mark, end_mark, flow_style)
637        elif event.type == YAML_SEQUENCE_END_EVENT:
638            return SequenceEndEvent(start_mark, end_mark)
639        elif event.type == YAML_MAPPING_END_EVENT:
640            return MappingEndEvent(start_mark, end_mark)
641
642        else:
643            raise ValueError("unknown token type")
644
645    def get_event(self):
646        if self.current_event is not None:
647            value = self.current_event
648            self.current_event = None
649        else:
650            value = self._parse()
651        return value
652
653    def peek_event(self):
654        if self.current_event is None:
655            self.current_event = self._parse()
656        return self.current_event
657
658    def check_event(self, *choices):
659        if self.current_event is None:
660            self.current_event = self._parse()
661        if self.current_event is None:
662            return False
663        if not choices:
664            return True
665        event_class = self.current_event.__class__
666        for choice in choices:
667            if event_class is choice:
668                return True
669        return False
670
671    def check_node(self):
672        self._parse_next_event()
673        if self.parsed_event.type == YAML_STREAM_START_EVENT:
674            yaml_event_delete(&self.parsed_event)
675            self._parse_next_event()
676        if self.parsed_event.type != YAML_STREAM_END_EVENT:
677            return True
678        return False
679
680    def get_node(self):
681        self._parse_next_event()
682        if self.parsed_event.type != YAML_STREAM_END_EVENT:
683            return self._compose_document()
684
685    def get_single_node(self):
686        self._parse_next_event()
687        yaml_event_delete(&self.parsed_event)
688        self._parse_next_event()
689        document = None
690        if self.parsed_event.type != YAML_STREAM_END_EVENT:
691            document = self._compose_document()
692        self._parse_next_event()
693        if self.parsed_event.type != YAML_STREAM_END_EVENT:
694            mark = Mark(self.stream_name,
695                    self.parsed_event.start_mark.index,
696                    self.parsed_event.start_mark.line,
697                    self.parsed_event.start_mark.column,
698                    None, None)
699            raise ComposerError("expected a single document in the stream",
700                    document.start_mark, "but found another document", mark)
701        return document
702
703    cdef object _compose_document(self):
704        yaml_event_delete(&self.parsed_event)
705        node = self._compose_node(None, None)
706        self._parse_next_event()
707        yaml_event_delete(&self.parsed_event)
708        self.anchors = {}
709        return node
710
711    cdef object _compose_node(self, object parent, object index):
712        self._parse_next_event()
713        if self.parsed_event.type == YAML_ALIAS_EVENT:
714            anchor = PyUnicode_DecodeUTF8(self.parsed_event.data.alias.anchor,
715                    strlen(self.parsed_event.data.alias.anchor), 'strict')
716            if anchor not in self.anchors:
717                mark = Mark(self.stream_name,
718                        self.parsed_event.start_mark.index,
719                        self.parsed_event.start_mark.line,
720                        self.parsed_event.start_mark.column,
721                        None, None)
722                raise ComposerError(None, None, "found undefined alias", mark)
723            yaml_event_delete(&self.parsed_event)
724            return self.anchors[anchor]
725        anchor = None
726        if self.parsed_event.type == YAML_SCALAR_EVENT  \
727                and self.parsed_event.data.scalar.anchor != NULL:
728            anchor = PyUnicode_DecodeUTF8(self.parsed_event.data.scalar.anchor,
729                    strlen(self.parsed_event.data.scalar.anchor), 'strict')
730        elif self.parsed_event.type == YAML_SEQUENCE_START_EVENT    \
731                and self.parsed_event.data.sequence_start.anchor != NULL:
732            anchor = PyUnicode_DecodeUTF8(self.parsed_event.data.sequence_start.anchor,
733                    strlen(self.parsed_event.data.sequence_start.anchor), 'strict')
734        elif self.parsed_event.type == YAML_MAPPING_START_EVENT    \
735                and self.parsed_event.data.mapping_start.anchor != NULL:
736            anchor = PyUnicode_DecodeUTF8(self.parsed_event.data.mapping_start.anchor,
737                    strlen(self.parsed_event.data.mapping_start.anchor), 'strict')
738        if anchor is not None:
739            if anchor in self.anchors:
740                mark = Mark(self.stream_name,
741                        self.parsed_event.start_mark.index,
742                        self.parsed_event.start_mark.line,
743                        self.parsed_event.start_mark.column,
744                        None, None)
745                raise ComposerError("found duplicate anchor; first occurence",
746                        self.anchors[anchor].start_mark, "second occurence", mark)
747        self.descend_resolver(parent, index)
748        if self.parsed_event.type == YAML_SCALAR_EVENT:
749            node = self._compose_scalar_node(anchor)
750        elif self.parsed_event.type == YAML_SEQUENCE_START_EVENT:
751            node = self._compose_sequence_node(anchor)
752        elif self.parsed_event.type == YAML_MAPPING_START_EVENT:
753            node = self._compose_mapping_node(anchor)
754        self.ascend_resolver()
755        return node
756
757    cdef _compose_scalar_node(self, object anchor):
758        start_mark = Mark(self.stream_name,
759                self.parsed_event.start_mark.index,
760                self.parsed_event.start_mark.line,
761                self.parsed_event.start_mark.column,
762                None, None)
763        end_mark = Mark(self.stream_name,
764                self.parsed_event.end_mark.index,
765                self.parsed_event.end_mark.line,
766                self.parsed_event.end_mark.column,
767                None, None)
768        value = PyUnicode_DecodeUTF8(self.parsed_event.data.scalar.value,
769                self.parsed_event.data.scalar.length, 'strict')
770        plain_implicit = False
771        if self.parsed_event.data.scalar.plain_implicit == 1:
772            plain_implicit = True
773        quoted_implicit = False
774        if self.parsed_event.data.scalar.quoted_implicit == 1:
775            quoted_implicit = True
776        if self.parsed_event.data.scalar.tag == NULL    \
777                or (self.parsed_event.data.scalar.tag[0] == c'!'
778                        and self.parsed_event.data.scalar.tag[1] == c'\0'):
779            tag = self.resolve(ScalarNode, value, (plain_implicit, quoted_implicit))
780        else:
781            tag = PyUnicode_DecodeUTF8(self.parsed_event.data.scalar.tag,
782                    strlen(self.parsed_event.data.scalar.tag), 'strict')
783        style = None
784        if self.parsed_event.data.scalar.style == YAML_PLAIN_SCALAR_STYLE:
785            style = ''
786        elif self.parsed_event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE:
787            style = '\''
788        elif self.parsed_event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE:
789            style = '"'
790        elif self.parsed_event.data.scalar.style == YAML_LITERAL_SCALAR_STYLE:
791            style = '|'
792        elif self.parsed_event.data.scalar.style == YAML_FOLDED_SCALAR_STYLE:
793            style = '>'
794        node = ScalarNode(tag, value, start_mark, end_mark, style)
795        if anchor is not None:
796            self.anchors[anchor] = node
797        yaml_event_delete(&self.parsed_event)
798        return node
799
800    cdef _compose_sequence_node(self, object anchor):
801        cdef int index
802        start_mark = Mark(self.stream_name,
803                self.parsed_event.start_mark.index,
804                self.parsed_event.start_mark.line,
805                self.parsed_event.start_mark.column,
806                None, None)
807        implicit = False
808        if self.parsed_event.data.sequence_start.implicit == 1:
809            implicit = True
810        if self.parsed_event.data.sequence_start.tag == NULL    \
811                or (self.parsed_event.data.sequence_start.tag[0] == c'!'
812                        and self.parsed_event.data.sequence_start.tag[1] == c'\0'):
813            tag = self.resolve(SequenceNode, None, implicit)
814        else:
815            tag = PyUnicode_DecodeUTF8(self.parsed_event.data.sequence_start.tag,
816                    strlen(self.parsed_event.data.sequence_start.tag), 'strict')
817        flow_style = None
818        if self.parsed_event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE:
819            flow_style = True
820        elif self.parsed_event.data.sequence_start.style == YAML_BLOCK_SEQUENCE_STYLE:
821            flow_style = False
822        value = []
823        node = SequenceNode(tag, value, start_mark, None, flow_style)
824        if anchor is not None:
825            self.anchors[anchor] = node
826        yaml_event_delete(&self.parsed_event)
827        index = 0
828        self._parse_next_event()
829        while self.parsed_event.type != YAML_SEQUENCE_END_EVENT:
830            value.append(self._compose_node(node, index))
831            index = index+1
832            self._parse_next_event()
833        node.end_mark = Mark(self.stream_name,
834                self.parsed_event.end_mark.index,
835                self.parsed_event.end_mark.line,
836                self.parsed_event.end_mark.column,
837                None, None)
838        yaml_event_delete(&self.parsed_event)
839        return node
840
841    cdef _compose_mapping_node(self, object anchor):
842        start_mark = Mark(self.stream_name,
843                self.parsed_event.start_mark.index,
844                self.parsed_event.start_mark.line,
845                self.parsed_event.start_mark.column,
846                None, None)
847        implicit = False
848        if self.parsed_event.data.mapping_start.implicit == 1:
849            implicit = True
850        if self.parsed_event.data.mapping_start.tag == NULL    \
851                or (self.parsed_event.data.mapping_start.tag[0] == c'!'
852                        and self.parsed_event.data.mapping_start.tag[1] == c'\0'):
853            tag = self.resolve(MappingNode, None, implicit)
854        else:
855            tag = PyUnicode_DecodeUTF8(self.parsed_event.data.mapping_start.tag,
856                    strlen(self.parsed_event.data.mapping_start.tag), 'strict')
857        flow_style = None
858        if self.parsed_event.data.mapping_start.style == YAML_FLOW_MAPPING_STYLE:
859            flow_style = True
860        elif self.parsed_event.data.mapping_start.style == YAML_BLOCK_MAPPING_STYLE:
861            flow_style = False
862        value = []
863        node = MappingNode(tag, value, start_mark, None, flow_style)
864        if anchor is not None:
865            self.anchors[anchor] = node
866        yaml_event_delete(&self.parsed_event)
867        self._parse_next_event()
868        while self.parsed_event.type != YAML_MAPPING_END_EVENT:
869            item_key = self._compose_node(node, None)
870            item_value = self._compose_node(node, item_key)
871            value.append((item_key, item_value))
872            self._parse_next_event()
873        node.end_mark = Mark(self.stream_name,
874                self.parsed_event.end_mark.index,
875                self.parsed_event.end_mark.line,
876                self.parsed_event.end_mark.column,
877                None, None)
878        yaml_event_delete(&self.parsed_event)
879        return node
880
881    cdef int _parse_next_event(self) except 0:
882        if self.parsed_event.type == YAML_NO_EVENT:
883            if yaml_parser_parse(&self.parser, &self.parsed_event) == 0:
884                error = self._parser_error()
885                raise error
886        return 1
887
888cdef int input_handler(void *data, char *buffer, int size, int *read) except 0:
889    cdef CParser parser
890    parser = <CParser>data
891    if parser.stream_cache is None:
892        value = parser.stream.read(size)
893        if PyUnicode_CheckExact(value) != 0:
894            value = PyUnicode_AsUTF8String(value)
895            parser.unicode_source = 1
896        if PyString_CheckExact(value) == 0:
897            raise TypeError("a string value is expected")
898        parser.stream_cache = value
899        parser.stream_cache_pos = 0
900        parser.stream_cache_len = PyString_GET_SIZE(value)
901    if (parser.stream_cache_len - parser.stream_cache_pos) < size:
902        size = parser.stream_cache_len - parser.stream_cache_pos
903    if size > 0:
904        memcpy(buffer, PyString_AS_STRING(parser.stream_cache)
905                            + parser.stream_cache_pos, size)
906    read[0] = size
907    parser.stream_cache_pos += size
908    if parser.stream_cache_pos == parser.stream_cache_len:
909        parser.stream_cache = None
910    return 1
911
912cdef class CEmitter:
913
914    cdef yaml_emitter_t emitter
915
916    cdef object stream
917
918    cdef int document_start_implicit
919    cdef int document_end_implicit
920    cdef object use_version
921    cdef object use_tags
922
923    cdef object serialized_nodes
924    cdef object anchors
925    cdef int last_alias_id
926    cdef int closed
927    cdef int dump_unicode
928    cdef object use_encoding
929
930    def __init__(self, stream, canonical=None, indent=None, width=None,
931            allow_unicode=None, line_break=None, encoding=None,
932            explicit_start=None, explicit_end=None, version=None, tags=None):
933        if yaml_emitter_initialize(&self.emitter) == 0:
934            raise MemoryError
935        self.stream = stream
936        self.dump_unicode = 0
937        try:
938            if stream.encoding:
939                self.dump_unicode = 1
940        except AttributeError:
941            pass
942        self.use_encoding = encoding
943        yaml_emitter_set_output(&self.emitter, output_handler, <void *>self)   
944        if canonical:
945            yaml_emitter_set_canonical(&self.emitter, 1)
946        if indent is not None:
947            yaml_emitter_set_indent(&self.emitter, indent)
948        if width is not None:
949            yaml_emitter_set_width(&self.emitter, width)
950        if allow_unicode:
951            yaml_emitter_set_unicode(&self.emitter, 1)
952        if line_break is not None:
953            if line_break == '\r':
954                yaml_emitter_set_break(&self.emitter, YAML_CR_BREAK)
955            elif line_break == '\n':
956                yaml_emitter_set_break(&self.emitter, YAML_LN_BREAK)
957            elif line_break == '\r\n':
958                yaml_emitter_set_break(&self.emitter, YAML_CRLN_BREAK)
959        self.document_start_implicit = 1
960        if explicit_start:
961            self.document_start_implicit = 0
962        self.document_end_implicit = 1
963        if explicit_end:
964            self.document_end_implicit = 0
965        self.use_version = version
966        self.use_tags = tags
967        self.serialized_nodes = {}
968        self.anchors = {}
969        self.last_alias_id = 0
970        self.closed = -1
971
972    def __dealloc__(self):
973        yaml_emitter_delete(&self.emitter)
974
975    cdef object _emitter_error(self):
976        if self.emitter.error == YAML_MEMORY_ERROR:
977            return MemoryError
978        elif self.emitter.error == YAML_EMITTER_ERROR:
979            return EmitterError(self.emitter.problem)
980        raise ValueError("no emitter error")
981
982    cdef int _object_to_event(self, object event_object, yaml_event_t *event) except 0:
983        cdef yaml_encoding_t encoding
984        cdef yaml_version_directive_t version_directive_value
985        cdef yaml_version_directive_t *version_directive
986        cdef yaml_tag_directive_t tag_directives_value[128]
987        cdef yaml_tag_directive_t *tag_directives_start
988        cdef yaml_tag_directive_t *tag_directives_end
989        cdef int implicit
990        cdef int plain_implicit
991        cdef int quoted_implicit
992        cdef char *anchor
993        cdef char *tag
994        cdef char *value
995        cdef int length
996        cdef yaml_scalar_style_t scalar_style
997        cdef yaml_sequence_style_t sequence_style
998        cdef yaml_mapping_style_t mapping_style
999        event_class = event_object.__class__
1000        if event_class is StreamStartEvent:
1001            encoding = YAML_UTF8_ENCODING
1002            if event_object.encoding == 'utf-16-le':
1003                encoding = YAML_UTF16LE_ENCODING
1004            elif event_object.encoding == 'utf-16-be':
1005                encoding = YAML_UTF16BE_ENCODING
1006            if event_object.encoding is None:
1007                self.dump_unicode = 1
1008            if self.dump_unicode == 1:
1009                encoding = YAML_UTF8_ENCODING
1010            yaml_stream_start_event_initialize(event, encoding)
1011        elif event_class is StreamEndEvent:
1012            yaml_stream_end_event_initialize(event)
1013        elif event_class is DocumentStartEvent:
1014            version_directive = NULL
1015            if event_object.version:
1016                version_directive_value.major = event_object.version[0]
1017                version_directive_value.minor = event_object.version[1]
1018                version_directive = &version_directive_value
1019            tag_directives_start = NULL
1020            tag_directives_end = NULL
1021            if event_object.tags:
1022                if len(event_object.tags) > 128:
1023                    raise ValueError("too many tags")
1024                tag_directives_start = tag_directives_value
1025                tag_directives_end = tag_directives_value
1026                cache = []
1027                for handle in event_object.tags:
1028                    prefix = event_object.tags[handle]
1029                    if PyUnicode_CheckExact(handle):
1030                        handle = PyUnicode_AsUTF8String(handle)
1031                        cache.append(handle)
1032                    if not PyString_CheckExact(handle):
1033                        raise TypeError("tag handle must be a string")
1034                    tag_directives_end.handle = PyString_AS_STRING(handle)
1035                    if PyUnicode_CheckExact(prefix):
1036                        prefix = PyUnicode_AsUTF8String(prefix)
1037                        cache.append(prefix)
1038                    if not PyString_CheckExact(prefix):
1039                        raise TypeError("tag prefix must be a string")
1040                    tag_directives_end.prefix = PyString_AS_STRING(prefix)
1041                    tag_directives_end = tag_directives_end+1
1042            implicit = 1
1043            if event_object.explicit:
1044                implicit = 0
1045            if yaml_document_start_event_initialize(event, version_directive,
1046                    tag_directives_start, tag_directives_end, implicit) == 0:
1047                raise MemoryError
1048        elif event_class is DocumentEndEvent:
1049            implicit = 1
1050            if event_object.explicit:
1051                implicit = 0
1052            yaml_document_end_event_initialize(event, implicit)
1053        elif event_class is AliasEvent:
1054            anchor = NULL
1055            anchor_object = event_object.anchor
1056            if PyUnicode_CheckExact(anchor_object):
1057                anchor_object = PyUnicode_AsUTF8String(anchor_object)
1058            if not PyString_CheckExact(anchor_object):
1059                raise TypeError("anchor must be a string")
1060            anchor = PyString_AS_STRING(anchor_object)
1061            if yaml_alias_event_initialize(event, anchor) == 0:
1062                raise MemoryError
1063        elif event_class is ScalarEvent:
1064            anchor = NULL
1065            anchor_object = event_object.anchor
1066            if anchor_object is not None:
1067                if PyUnicode_CheckExact(anchor_object):
1068                    anchor_object = PyUnicode_AsUTF8String(anchor_object)
1069                if not PyString_CheckExact(anchor_object):
1070                    raise TypeError("anchor must be a string")
1071                anchor = PyString_AS_STRING(anchor_object)
1072            tag = NULL
1073            tag_object = event_object.tag
1074            if tag_object is not None:
1075                if PyUnicode_CheckExact(tag_object):
1076                    tag_object = PyUnicode_AsUTF8String(tag_object)
1077                if not PyString_CheckExact(tag_object):
1078                    raise TypeError("tag must be a string")
1079                tag = PyString_AS_STRING(tag_object)
1080            value_object = event_object.value
1081            if PyUnicode_CheckExact(value_object):
1082                value_object = PyUnicode_AsUTF8String(value_object)
1083            if not PyString_CheckExact(value_object):
1084                raise TypeError("value must be a string")
1085            value = PyString_AS_STRING(value_object)
1086            length = PyString_GET_SIZE(value_object)
1087            plain_implicit = 0
1088            quoted_implicit = 0
1089            if event_object.implicit is not None:
1090                plain_implicit = event_object.implicit[0]
1091                quoted_implicit = event_object.implicit[1]
1092            style_object = event_object.style
1093            scalar_style = YAML_PLAIN_SCALAR_STYLE
1094            if style_object == "'":
1095                scalar_style = YAML_SINGLE_QUOTED_SCALAR_STYLE
1096            elif style_object == "\"":
1097                scalar_style = YAML_DOUBLE_QUOTED_SCALAR_STYLE
1098            elif style_object == "|":
1099                scalar_style = YAML_LITERAL_SCALAR_STYLE
1100            elif style_object == ">":
1101                scalar_style = YAML_FOLDED_SCALAR_STYLE
1102            if yaml_scalar_event_initialize(event, anchor, tag, value, length,
1103                    plain_implicit, quoted_implicit, scalar_style) == 0:
1104                raise MemoryError
1105        elif event_class is SequenceStartEvent:
1106            anchor = NULL
1107            anchor_object = event_object.anchor
1108            if anchor_object is not None:
1109                if PyUnicode_CheckExact(anchor_object):
1110                    anchor_object = PyUnicode_AsUTF8String(anchor_object)
1111                if not PyString_CheckExact(anchor_object):
1112                    raise TypeError("anchor must be a string")
1113                anchor = PyString_AS_STRING(anchor_object)
1114            tag = NULL
1115            tag_object = event_object.tag
1116            if tag_object is not None:
1117                if PyUnicode_CheckExact(tag_object):
1118                    tag_object = PyUnicode_AsUTF8String(tag_object)
1119                if not PyString_CheckExact(tag_object):
1120                    raise TypeError("tag must be a string")
1121                tag = PyString_AS_STRING(tag_object)
1122            implicit = 0
1123            if event_object.implicit:
1124                implicit = 1
1125            sequence_style = YAML_BLOCK_SEQUENCE_STYLE
1126            if event_object.flow_style:
1127                sequence_style = YAML_FLOW_SEQUENCE_STYLE
1128            if yaml_sequence_start_event_initialize(event, anchor, tag,
1129                    implicit, sequence_style) == 0:
1130                raise MemoryError
1131        elif event_class is MappingStartEvent:
1132            anchor = NULL
1133            anchor_object = event_object.anchor
1134            if anchor_object is not None:
1135                if PyUnicode_CheckExact(anchor_object):
1136                    anchor_object = PyUnicode_AsUTF8String(anchor_object)
1137                if not PyString_CheckExact(anchor_object):
1138                    raise TypeError("anchor must be a string")
1139                anchor = PyString_AS_STRING(anchor_object)
1140            tag = NULL
1141            tag_object = event_object.tag
1142            if tag_object is not None:
1143                if PyUnicode_CheckExact(tag_object):
1144                    tag_object = PyUnicode_AsUTF8String(tag_object)
1145                if not PyString_CheckExact(tag_object):
1146                    raise TypeError("tag must be a string")
1147                tag = PyString_AS_STRING(tag_object)
1148            implicit = 0
1149            if event_object.implicit:
1150                implicit = 1
1151            mapping_style = YAML_BLOCK_MAPPING_STYLE
1152            if event_object.flow_style:
1153                mapping_style = YAML_FLOW_MAPPING_STYLE
1154            if yaml_mapping_start_event_initialize(event, anchor, tag,
1155                    implicit, mapping_style) == 0:
1156                raise MemoryError
1157        elif event_class is SequenceEndEvent:
1158            yaml_sequence_end_event_initialize(event)
1159        elif event_class is MappingEndEvent:
1160            yaml_mapping_end_event_initialize(event)
1161        else:
1162            raise TypeError("invalid event %s" % event_object)
1163        return 1
1164
1165    def emit(self, event_object):
1166        cdef yaml_event_t event
1167        self._object_to_event(event_object, &event)
1168        if yaml_emitter_emit(&self.emitter, &event) == 0:
1169            error = self._emitter_error()
1170            raise error
1171
1172    def open(self):
1173        cdef yaml_event_t event
1174        cdef yaml_encoding_t encoding
1175        if self.closed == -1:
1176            if self.use_encoding == 'utf-16-le':
1177                encoding = YAML_UTF16LE_ENCODING
1178            elif self.use_encoding == 'utf-16-be':
1179                encoding = YAML_UTF16BE_ENCODING
1180            else:
1181                encoding = YAML_UTF8_ENCODING
1182            if self.use_encoding is None:
1183                self.dump_unicode = 1
1184            if self.dump_unicode == 1:
1185                encoding = YAML_UTF8_ENCODING
1186            yaml_stream_start_event_initialize(&event, encoding)
1187            if yaml_emitter_emit(&self.emitter, &event) == 0:
1188                error = self._emitter_error()
1189                raise error
1190            self.closed = 0
1191        elif self.closed == 1:
1192            raise SerializerError("serializer is closed")
1193        else:
1194            raise SerializerError("serializer is already opened")
1195
1196    def close(self):
1197        cdef yaml_event_t event
1198        if self.closed == -1:
1199            raise SerializerError("serializer is not opened")
1200        elif self.closed == 0:
1201            yaml_stream_end_event_initialize(&event)
1202            if yaml_emitter_emit(&self.emitter, &event) == 0:
1203                error = self._emitter_error()
1204                raise error
1205            self.closed = 1
1206
1207    def serialize(self, node):
1208        cdef yaml_event_t event
1209        cdef yaml_version_directive_t version_directive_value
1210        cdef yaml_version_directive_t *version_directive
1211        cdef yaml_tag_directive_t tag_directives_value[128]
1212        cdef yaml_tag_directive_t *tag_directives_start
1213        cdef yaml_tag_directive_t *tag_directives_end
1214        if self.closed == -1:
1215            raise SerializerError("serializer is not opened")
1216        elif self.closed == 1:
1217            raise SerializerError("serializer is closed")
1218        cache = []
1219        version_directive = NULL
1220        if self.use_version:
1221            version_directive_value.major = self.use_version[0]
1222            version_directive_value.minor = self.use_version[1]
1223            version_directive = &version_directive_value
1224        tag_directives_start = NULL
1225        tag_directives_end = NULL
1226        if self.use_tags:
1227            if len(self.use_tags) > 128:
1228                raise ValueError("too many tags")
1229            tag_directives_start = tag_directives_value
1230            tag_directives_end = tag_directives_value
1231            for handle in self.use_tags:
1232                prefix = self.use_tags[handle]
1233                if PyUnicode_CheckExact(handle):
1234                    handle = PyUnicode_AsUTF8String(handle)
1235                    cache.append(handle)
1236                if not PyString_CheckExact(handle):
1237                    raise TypeError("tag handle must be a string")
1238                tag_directives_end.handle = PyString_AS_STRING(handle)
1239                if PyUnicode_CheckExact(prefix):
1240                    prefix = PyUnicode_AsUTF8String(prefix)
1241                    cache.append(prefix)
1242                if not PyString_CheckExact(prefix):
1243                    raise TypeError("tag prefix must be a string")
1244                tag_directives_end.prefix = PyString_AS_STRING(prefix)
1245                tag_directives_end = tag_directives_end+1
1246        if yaml_document_start_event_initialize(&event, version_directive,
1247                tag_directives_start, tag_directives_end,
1248                self.document_start_implicit) == 0:
1249            raise MemoryError
1250        if yaml_emitter_emit(&self.emitter, &event) == 0:
1251            error = self._emitter_error()
1252            raise error
1253        self._anchor_node(node)
1254        self._serialize_node(node, None, None)
1255        yaml_document_end_event_initialize(&event, self.document_end_implicit)
1256        if yaml_emitter_emit(&self.emitter, &event) == 0:
1257            error = self._emitter_error()
1258            raise error
1259        self.serialized_nodes = {}
1260        self.anchors = {}
1261        self.last_alias_id = 0
1262
1263    cdef int _anchor_node(self, object node) except 0:
1264        if node in self.anchors:
1265            if self.anchors[node] is None:
1266                self.last_alias_id = self.last_alias_id+1
1267                self.anchors[node] = u"id%03d" % self.last_alias_id
1268        else:
1269            self.anchors[node] = None
1270            node_class = node.__class__
1271            if node_class is SequenceNode:
1272                for item in node.value:
1273                    self._anchor_node(item)
1274            elif node_class is MappingNode:
1275                for key, value in node.value:
1276                    self._anchor_node(key)
1277                    self._anchor_node(value)
1278        return 1
1279
1280    cdef int _serialize_node(self, object node, object parent, object index) except 0:
1281        cdef yaml_event_t event
1282        cdef int implicit
1283        cdef int plain_implicit
1284        cdef int quoted_implicit
1285        cdef char *anchor
1286        cdef char *tag
1287        cdef char *value
1288        cdef int length
1289        cdef int item_index
1290        cdef yaml_scalar_style_t scalar_style
1291        cdef yaml_sequence_style_t sequence_style
1292        cdef yaml_mapping_style_t mapping_style
1293        anchor_object = self.anchors[node]
1294        anchor = NULL
1295        if anchor_object is not None:
1296            anchor = PyString_AS_STRING(PyUnicode_AsUTF8String(anchor_object))
1297        if node in self.serialized_nodes:
1298            if yaml_alias_event_initialize(&event, anchor) == 0:
1299                raise MemoryError
1300            if yaml_emitter_emit(&self.emitter, &event) == 0:
1301                error = self._emitter_error()
1302                raise error
1303        else:
1304            node_class = node.__class__
1305            self.serialized_nodes[node] = True
1306            self.descend_resolver(parent, index)
1307            if node_class is ScalarNode:
1308                plain_implicit = 0
1309                quoted_implicit = 0
1310                tag_object = node.tag
1311                if self.resolve(ScalarNode, node.value, (True, False)) == tag_object:
1312                    plain_implicit = 1
1313                if self.resolve(ScalarNode, node.value, (False, True)) == tag_object:
1314                    quoted_implicit = 1
1315                tag = NULL
1316                if tag_object is not None:
1317                    if PyUnicode_CheckExact(tag_object):
1318                        tag_object = PyUnicode_AsUTF8String(tag_object)
1319                    if not PyString_CheckExact(tag_object):
1320                        raise TypeError("tag must be a string")
1321                    tag = PyString_AS_STRING(tag_object)
1322                value_object = node.value
1323                if PyUnicode_CheckExact(value_object):
1324                    value_object = PyUnicode_AsUTF8String(value_object)
1325                if not PyString_CheckExact(value_object):
1326                    raise TypeError("value must be a string")
1327                value = PyString_AS_STRING(value_object)
1328                length = PyString_GET_SIZE(value_object)
1329                style_object = node.style
1330                scalar_style = YAML_PLAIN_SCALAR_STYLE
1331                if style_object == "'":
1332                    scalar_style = YAML_SINGLE_QUOTED_SCALAR_STYLE
1333                elif style_object == "\"":
1334                    scalar_style = YAML_DOUBLE_QUOTED_SCALAR_STYLE
1335                elif style_object == "|":
1336                    scalar_style = YAML_LITERAL_SCALAR_STYLE
1337                elif style_object == ">":
1338                    scalar_style = YAML_FOLDED_SCALAR_STYLE
1339                if yaml_scalar_event_initialize(&event, anchor, tag, value, length,
1340                        plain_implicit, quoted_implicit, scalar_style) == 0:
1341                    raise MemoryError
1342                if yaml_emitter_emit(&self.emitter, &event) == 0:
1343                    error = self._emitter_error()
1344                    raise error
1345            elif node_class is SequenceNode:
1346                implicit = 0
1347                tag_object = node.tag
1348                if self.resolve(SequenceNode, node.value, True) == tag_object:
1349                    implicit = 1
1350                tag = NULL
1351                if tag_object is not None:
1352                    if PyUnicode_CheckExact(tag_object):
1353                        tag_object = PyUnicode_AsUTF8String(tag_object)
1354                    if not PyString_CheckExact(tag_object):
1355                        raise TypeError("tag must be a string")
1356                    tag = PyString_AS_STRING(tag_object)
1357                sequence_style = YAML_BLOCK_SEQUENCE_STYLE
1358                if node.flow_style:
1359                    sequence_style = YAML_FLOW_SEQUENCE_STYLE
1360                if yaml_sequence_start_event_initialize(&event, anchor, tag,
1361                        implicit, sequence_style) == 0:
1362                    raise MemoryError
1363                if yaml_emitter_emit(&self.emitter, &event) == 0:
1364                    error = self._emitter_error()
1365                    raise error
1366                item_index = 0
1367                for item in node.value:
1368                    self._serialize_node(item, node, item_index)
1369                    item_index = item_index+1
1370                yaml_sequence_end_event_initialize(&event)
1371                if yaml_emitter_emit(&self.emitter, &event) == 0:
1372                    error = self._emitter_error()
1373                    raise error
1374            elif node_class is MappingNode:
1375                implicit = 0
1376                tag_object = node.tag
1377                if self.resolve(MappingNode, node.value, True) == tag_object:
1378                    implicit = 1
1379                tag = NULL
1380                if tag_object is not None:
1381                    if PyUnicode_CheckExact(tag_object):
1382                        tag_object = PyUnicode_AsUTF8String(tag_object)
1383                    if not PyString_CheckExact(tag_object):
1384                        raise TypeError("tag must be a string")
1385                    tag = PyString_AS_STRING(tag_object)
1386                mapping_style = YAML_BLOCK_MAPPING_STYLE
1387                if node.flow_style:
1388                    mapping_style = YAML_FLOW_MAPPING_STYLE
1389                if yaml_mapping_start_event_initialize(&event, anchor, tag,
1390                        implicit, mapping_style) == 0:
1391                    raise MemoryError
1392                if yaml_emitter_emit(&self.emitter, &event) == 0:
1393                    error = self._emitter_error()
1394                    raise error
1395                for item_key, item_value in node.value:
1396                    self._serialize_node(item_key, node, None)
1397                    self._serialize_node(item_value, node, item_key)
1398                yaml_mapping_end_event_initialize(&event)
1399                if yaml_emitter_emit(&self.emitter, &event) == 0:
1400                    error = self._emitter_error()
1401                    raise error
1402            self.ascend_resolver()
1403        return 1
1404
1405cdef int output_handler(void *data, char *buffer, int size) except 0:
1406    cdef CEmitter emitter
1407    emitter = <CEmitter>data
1408    if emitter.dump_unicode == 0:
1409        value = PyString_FromStringAndSize(buffer, size)
1410    else:
1411        value = PyUnicode_DecodeUTF8(buffer, size, 'strict')
1412    emitter.stream.write(value)
1413    return 1
1414
Note: See TracBrowser for help on using the repository browser.