source: trunk/packages/pyyaml/ext/_yaml.pyx @ 1260

Last change on this file since 1260 was 898, checked in by hartmans, 16 years ago

Add pyyaml and libyaml packages
backported from lenny.
There is discussion about how these should go in the repository; these are added in this form
in order to make forward progress.

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