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

Revision 331, 57.3 KB checked in by xi, 5 years ago (diff)

Use Cython if available; added Python 3 support to _yaml.pyx.

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