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

Revision 209, 22.0 KB checked in by xi, 8 years ago (diff)

Update libyaml bindings.

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
12def test_scanner(stream):
13    cdef yaml_parser_t parser
14    cdef yaml_token_t token
15    cdef int done
16    cdef int count
17    if hasattr(stream, 'read'):
18        stream = stream.read()
19    if PyUnicode_CheckExact(stream) != 0:
20        stream = stream.encode('utf-8')
21    if PyString_CheckExact(stream) == 0:
22        raise TypeError("a string or stream input is required")
23    if yaml_parser_initialize(&parser) == 0:
24        raise RuntimeError("cannot initialize parser")
25    yaml_parser_set_input_string(&parser, PyString_AS_STRING(stream), PyString_GET_SIZE(stream))
26    done = 0
27    count = 0
28    while done == 0:
29        if yaml_parser_scan(&parser, &token) == 0:
30            raise RuntimeError("cannot get next token: #%s" % count)
31        if token.type == YAML_NO_TOKEN:
32            done = 1
33        else:
34            count = count+1
35        yaml_token_delete(&token)
36    yaml_parser_delete(&parser)
37    dummy = len(stream)
38    return count
39
40def test_parser(stream):
41    cdef yaml_parser_t parser
42    cdef yaml_event_t event
43    cdef int done
44    cdef int count
45    if hasattr(stream, 'read'):
46        stream = stream.read()
47    if PyUnicode_CheckExact(stream) != 0:
48        stream = stream.encode('utf-8')
49    if PyString_CheckExact(stream) == 0:
50        raise TypeError("a string or stream input is required")
51    if yaml_parser_initialize(&parser) == 0:
52        raise RuntimeError("cannot initialize parser")
53    yaml_parser_set_input_string(&parser, PyString_AS_STRING(stream), PyString_GET_SIZE(stream))
54    done = 0
55    count = 0
56    while done == 0:
57        if yaml_parser_parse(&parser, &event) == 0:
58            raise RuntimeError("cannot get next event: #%s" % count)
59        if event.type == YAML_NO_EVENT:
60            done = 1
61        else:
62            count = count+1
63        yaml_event_delete(&event)
64    yaml_parser_delete(&parser)
65    dummy = len(stream)
66    return count
67
68cdef class ScannerAndParser:
69
70    cdef yaml_parser_t parser
71
72    cdef object stream
73    cdef object current_token
74    cdef object current_event
75
76    cdef object cached_input
77    cdef object cached_YAML
78    cdef object cached_TAG
79    cdef object cached_question
80    cdef object cached_Mark
81    cdef object cached_ReaderError
82    cdef object cached_ScannerError
83    cdef object cached_ParserError
84    cdef object cached_StreamStartToken
85    cdef object cached_StreamEndToken
86    cdef object cached_DirectiveToken
87    cdef object cached_DocumentStartToken
88    cdef object cached_DocumentEndToken
89    cdef object cached_BlockSequenceStartToken
90    cdef object cached_BlockMappingStartToken
91    cdef object cached_BlockEndToken
92    cdef object cached_FlowSequenceStartToken
93    cdef object cached_FlowMappingStartToken
94    cdef object cached_FlowSequenceEndToken
95    cdef object cached_FlowMappingEndToken
96    cdef object cached_BlockEntryToken
97    cdef object cached_FlowEntryToken
98    cdef object cached_KeyToken
99    cdef object cached_ValueToken
100    cdef object cached_AliasToken
101    cdef object cached_AnchorToken
102    cdef object cached_TagToken
103    cdef object cached_ScalarToken
104    cdef object cached_StreamStartEvent
105    cdef object cached_StreamEndEvent
106    cdef object cached_DocumentStartEvent
107    cdef object cached_DocumentEndEvent
108    cdef object cached_AliasEvent
109    cdef object cached_SequenceStartEvent
110    cdef object cached_SequenceEndEvent
111    cdef object cached_MappingStartEvent
112    cdef object cached_MappingEndEvent
113
114    def __init__(self, stream):
115        if yaml_parser_initialize(&self.parser) == 0:
116            raise MemoryError
117        if hasattr(stream, 'read'):
118            self.stream = stream
119            yaml_parser_set_input(&self.parser, input_handler, <void *>self)
120        else:
121            if PyUnicode_CheckExact(stream) != 0:
122                stream = PyUnicode_AsUTF8String(stream)
123            if PyString_CheckExact(stream) == 0:
124                raise TypeError("a string or stream input is required")
125            self.stream = stream
126            yaml_parser_set_input_string(&self.parser, PyString_AS_STRING(stream), PyString_GET_SIZE(stream))
127        self.current_token = None
128        self._cache_names()
129
130    def get_token(self):
131        if self.current_token is not None:
132            value = self.current_token
133            self.current_token = None
134        else:
135            value = self._scan()
136        return value
137
138    def peek_token(self):
139        if self.current_token is None:
140            self.current_token = self._scan()
141        return self.current_token
142
143    def check_token(self, *choices):
144        if self.current_token is None:
145            self.current_token = self._scan()
146        if self.current_token is None:
147            return False
148        if not choices:
149            return True
150        token_class = self.current_token.__class__
151        for choice in choices:
152            if token_class is choice:
153                return True
154        return False
155
156    def get_event(self):
157        if self.current_event is not None:
158            value = self.current_event
159            self.current_event = None
160        else:
161            value = self._parse()
162        return value
163
164    def peek_event(self):
165        if self.current_event is None:
166            self.current_event = self._parse()
167        return self.current_event
168
169    def check_event(self, *choices):
170        if self.current_event is None:
171            self.current_event = self._parse()
172        if self.current_event is None:
173            return False
174        if not choices:
175            return True
176        event_class = self.current_event.__class__
177        for choice in choices:
178            if event_class is choice:
179                return True
180        return False
181
182    def __dealloc__(self):
183        yaml_parser_delete(&self.parser)
184
185    cdef object _cache_names(self):
186        self.cached_input = '<input>'
187        self.cached_YAML = 'YAML'
188        self.cached_TAG = 'TAG'
189        self.cached_question = '?'
190        self.cached_Mark = yaml.Mark
191        self.cached_ReaderError = yaml.reader.ReaderError
192        self.cached_ScannerError = yaml.scanner.ScannerError
193        self.cached_ParserError = yaml.parser.ParserError
194        self.cached_StreamStartToken = yaml.StreamStartToken
195        self.cached_StreamEndToken = yaml.StreamEndToken
196        self.cached_DirectiveToken = yaml.DirectiveToken
197        self.cached_DocumentStartToken = yaml.DocumentStartToken
198        self.cached_DocumentEndToken = yaml.DocumentEndToken
199        self.cached_BlockSequenceStartToken = yaml.BlockSequenceStartToken
200        self.cached_BlockMappingStartToken = yaml.BlockMappingStartToken
201        self.cached_BlockEndToken = yaml.BlockEndToken
202        self.cached_FlowSequenceStartToken = yaml.FlowSequenceStartToken
203        self.cached_FlowMappingStartToken = yaml.FlowMappingStartToken
204        self.cached_FlowSequenceEndToken = yaml.FlowSequenceEndToken
205        self.cached_FlowMappingEndToken = yaml.FlowMappingEndToken
206        self.cached_BlockEntryToken = yaml.BlockEntryToken
207        self.cached_FlowEntryToken = yaml.FlowEntryToken
208        self.cached_KeyToken = yaml.KeyToken
209        self.cached_ValueToken = yaml.ValueToken
210        self.cached_AliasToken = yaml.AliasToken
211        self.cached_AnchorToken = yaml.AnchorToken
212        self.cached_TagToken = yaml.TagToken
213        self.cached_ScalarToken = yaml.ScalarToken
214        self.cached_StreamStartEvent = yaml.StreamStartEvent
215        self.cached_StreamEndEvent = yaml.StreamEndEvent
216        self.cached_DocumentStartEvent = yaml.DocumentStartEvent
217        self.cached_DocumentEndEvent = yaml.DocumentEndEvent
218        self.cached_AliasEvent = yaml.AliasEvent
219        self.cached_ScalarEvent = yaml.ScalarEvent
220        self.cached_SequenceStartEvent = yaml.SequenceStartEvent
221        self.cached_SequenceEndEvent = yaml.SequenceEndEvent
222        self.cached_MappingStartEvent = yaml.MappingStartEvent
223        self.cached_MappingEndEvent = yaml.MappingEndEvent
224
225    cdef object _scan(self):
226        cdef yaml_token_t token
227        if yaml_parser_scan(&self.parser, &token) == 0:
228            if self.parser.error == YAML_MEMORY_ERROR:
229                raise MemoryError
230            elif self.parser.error == YAML_READER_ERROR:
231                raise self.cached_ReaderError(self.cached_input,
232                        self.parser.problem_offset,
233                        self.parser.problem_value,
234                        self.cached_question, self.parser.problem)
235            elif self.parser.error == YAML_SCANNER_ERROR:
236                context_mark = None
237                problem_mark = None
238                if self.parser.context != NULL:
239                    context_mark = self.cached_Mark(self.cached_input,
240                            self.parser.context_mark.index,
241                            self.parser.context_mark.line,
242                            self.parser.context_mark.column,
243                            None, None)
244                if self.parser.problem != NULL:
245                    problem_mark = self.cached_Mark(self.cached_input,
246                            self.parser.problem_mark.index,
247                            self.parser.problem_mark.line,
248                            self.parser.problem_mark.column,
249                            None, None)
250                if self.parser.context != NULL:
251                    raise self.cached_ScannerError(
252                            self.parser.context, context_mark,
253                            self.parser.problem, problem_mark)
254                else:
255                    raise yaml.scanner.ScannerError(None, None,
256                            self.parser.problem, problem_mark)
257        start_mark = yaml.Mark(self.cached_input,
258                token.start_mark.index,
259                token.start_mark.line,
260                token.start_mark.column,
261                None, None)
262        end_mark = yaml.Mark(self.cached_input,
263                token.end_mark.index,
264                token.end_mark.line,
265                token.end_mark.column,
266                None, None)
267        if token.type == YAML_NO_TOKEN:
268            return None
269        elif token.type == YAML_STREAM_START_TOKEN:
270            return self.cached_StreamStartToken(start_mark, end_mark)
271        elif token.type == YAML_STREAM_END_TOKEN:
272            return self.cached_StreamEndToken(start_mark, end_mark)
273        elif token.type == YAML_VERSION_DIRECTIVE_TOKEN:
274            return self.cached_DirectiveToken(self.cached_YAML,
275                    (token.data.version_directive.major,
276                        token.data.version_directive.minor),
277                    start_mark, end_mark)
278        elif token.type == YAML_TAG_DIRECTIVE_TOKEN:
279            return self.cached_DirectiveToken(self.cached_TAG,
280                    (token.data.tag_directive.handle,
281                        token.data.tag_directive.prefix),
282                    start_mark, end_mark)
283        elif token.type == YAML_DOCUMENT_START_TOKEN:
284            return self.cached_DocumentStartToken(start_mark, end_mark)
285        elif token.type == YAML_DOCUMENT_END_TOKEN:
286            return self.cached_DocumentEndToken(start_mark, end_mark)
287        elif token.type == YAML_BLOCK_SEQUENCE_START_TOKEN:
288            return self.cached_BlockSequenceStartToken(start_mark, end_mark)
289        elif token.type == YAML_BLOCK_MAPPING_START_TOKEN:
290            return self.cached_BlockMappingStartToken(start_mark, end_mark)
291        elif token.type == YAML_BLOCK_END_TOKEN:
292            return self.cached_BlockEndToken(start_mark, end_mark)
293        elif token.type == YAML_FLOW_SEQUENCE_START_TOKEN:
294            return self.cached_FlowSequenceStartToken(start_mark, end_mark)
295        elif token.type == YAML_FLOW_SEQUENCE_END_TOKEN:
296            return self.cached_FlowSequenceEndToken(start_mark, end_mark)
297        elif token.type == YAML_FLOW_MAPPING_START_TOKEN:
298            return self.cached_FlowMappingStartToken(start_mark, end_mark)
299        elif token.type == YAML_FLOW_MAPPING_END_TOKEN:
300            return self.cached_FlowMappingEndToken(start_mark, end_mark)
301        elif token.type == YAML_BLOCK_ENTRY_TOKEN:
302            return self.cached_BlockEntryToken(start_mark, end_mark)
303        elif token.type == YAML_FLOW_ENTRY_TOKEN:
304            return self.cached_FlowEntryToken(start_mark, end_mark)
305        elif token.type == YAML_KEY_TOKEN:
306            return self.cached_KeyToken(start_mark, end_mark)
307        elif token.type == YAML_VALUE_TOKEN:
308            return self.cached_ValueToken(start_mark, end_mark)
309        elif token.type == YAML_ALIAS_TOKEN:
310            value = PyUnicode_DecodeUTF8(token.data.alias.value,
311                    strlen(token.data.alias.value), 'strict')
312            return self.cached_AliasToken(value, start_mark, end_mark)
313        elif token.type == YAML_ANCHOR_TOKEN:
314            value = PyUnicode_DecodeUTF8(token.data.anchor.value,
315                    strlen(token.data.anchor.value), 'strict')
316            return self.cached_AnchorToken(value, start_mark, end_mark)
317        elif token.type == YAML_TAG_TOKEN:
318            handle = PyUnicode_DecodeUTF8(token.data.tag.handle,
319                    strlen(token.data.tag.handle), 'strict')
320            suffix = PyUnicode_DecodeUTF8(token.data.tag.suffix,
321                    strlen(token.data.tag.suffix), 'strict')
322            if not handle:
323                handle = None
324            return self.cached_TagToken((handle, suffix), start_mark, end_mark)
325        elif token.type == YAML_SCALAR_TOKEN:
326            value = PyUnicode_DecodeUTF8(token.data.scalar.value,
327                    token.data.scalar.length, 'strict')
328            plain = False
329            style = None
330            if token.data.scalar.style == YAML_PLAIN_SCALAR_STYLE:
331                plain = True
332                style = ''
333            elif token.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE:
334                style = '\''
335            elif token.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE:
336                style = '"'
337            elif token.data.scalar.style == YAML_LITERAL_SCALAR_STYLE:
338                style = '|'
339            elif token.data.scalar.style == YAML_FOLDED_SCALAR_STYLE:
340                style = '>'
341            return self.cached_ScalarToken(value, plain,
342                    start_mark, end_mark, style)
343        else:
344            raise RuntimeError("unknown token type")
345
346    cdef object _parse(self):
347        cdef yaml_event_t event
348        if yaml_parser_parse(&self.parser, &event) == 0:
349            if self.parser.error == YAML_MEMORY_ERROR:
350                raise MemoryError
351            elif self.parser.error == YAML_READER_ERROR:
352                raise self.cached_ReaderError(self.cached_input,
353                        self.parser.problem_offset,
354                        self.parser.problem_value,
355                        self.cached_question, self.parser.problem)
356            elif self.parser.error == YAML_SCANNER_ERROR    \
357                    or self.parser.error == YAML_PARSER_ERROR:
358                context_mark = None
359                problem_mark = None
360                if self.parser.context != NULL:
361                    context_mark = self.cached_Mark(self.cached_input,
362                            self.parser.context_mark.index,
363                            self.parser.context_mark.line,
364                            self.parser.context_mark.column,
365                            None, None)
366                if self.parser.problem != NULL:
367                    problem_mark = self.cached_Mark(self.cached_input,
368                            self.parser.problem_mark.index,
369                            self.parser.problem_mark.line,
370                            self.parser.problem_mark.column,
371                            None, None)
372                if self.parser.error == YAML_SCANNER_ERROR:
373                    if self.parser.context != NULL:
374                        raise self.cached_ScannerError(
375                                self.parser.context, context_mark,
376                                self.parser.problem, problem_mark)
377                    else:
378                        raise self.cached_ScannerError(None, None,
379                                self.parser.problem, problem_mark)
380                else:
381                    if self.parser.context != NULL:
382                        raise self.cached_ParserError(
383                                self.parser.context, context_mark,
384                                self.parser.problem, problem_mark)
385                    else:
386                        raise self.cached_ParserError(None, None,
387                                self.parser.problem, problem_mark)
388        start_mark = yaml.Mark(self.cached_input,
389                event.start_mark.index,
390                event.start_mark.line,
391                event.start_mark.column,
392                None, None)
393        end_mark = yaml.Mark(self.cached_input,
394                event.end_mark.index,
395                event.end_mark.line,
396                event.end_mark.column,
397                None, None)
398        if event.type == YAML_NO_EVENT:
399            return None
400        elif event.type == YAML_STREAM_START_EVENT:
401            return self.cached_StreamStartEvent(start_mark, end_mark)
402        elif event.type == YAML_STREAM_END_EVENT:
403            return self.cached_StreamEndEvent(start_mark, end_mark)
404        elif event.type == YAML_DOCUMENT_START_EVENT:
405            return self.cached_DocumentStartEvent(start_mark, end_mark)
406        elif event.type == YAML_DOCUMENT_END_EVENT:
407            return self.cached_DocumentEndEvent(start_mark, end_mark)
408        elif event.type == YAML_ALIAS_EVENT:
409            anchor = PyUnicode_DecodeUTF8(event.data.alias.anchor,
410                    strlen(event.data.alias.anchor), 'strict')
411            return self.cached_AliasEvent(anchor, start_mark, end_mark)
412        elif event.type == YAML_SCALAR_EVENT:
413            anchor = None
414            if event.data.scalar.anchor != NULL:
415                anchor = PyUnicode_DecodeUTF8(event.data.scalar.anchor,
416                        strlen(event.data.scalar.anchor), 'strict')
417            tag = None
418            if event.data.scalar.tag != NULL:
419                tag = PyUnicode_DecodeUTF8(event.data.scalar.tag,
420                        strlen(event.data.scalar.tag), 'strict')
421            value = PyUnicode_DecodeUTF8(event.data.scalar.value,
422                    event.data.scalar.length, 'strict')
423            plain_implicit = (event.data.scalar.plain_implicit == 1)
424            quoted_implicit = (event.data.scalar.quoted_implicit == 1)
425            style = None
426            if event.data.scalar.style == YAML_PLAIN_SCALAR_STYLE:
427                style = ''
428            elif event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE:
429                style = '\''
430            elif event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE:
431                style = '"'
432            elif event.data.scalar.style == YAML_LITERAL_SCALAR_STYLE:
433                style = '|'
434            elif event.data.scalar.style == YAML_FOLDED_SCALAR_STYLE:
435                style = '>'
436            return self.cached_ScalarEvent(anchor, tag,
437                    (plain_implicit, quoted_implicit),
438                    value, start_mark, end_mark, style)
439        elif event.type == YAML_SEQUENCE_START_EVENT:
440            anchor = None
441            if event.data.sequence_start.anchor != NULL:
442                anchor = PyUnicode_DecodeUTF8(event.data.sequence_start.anchor,
443                        strlen(event.data.sequence_start.anchor), 'strict')
444            tag = None
445            if event.data.sequence_start.tag != NULL:
446                tag = PyUnicode_DecodeUTF8(event.data.sequence_start.tag,
447                        strlen(event.data.sequence_start.tag), 'strict')
448            implicit = (event.data.sequence_start.implicit == 1)
449            flow_style = None
450            if event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE:
451                flow_style = True
452            elif event.data.sequence_start.style == YAML_BLOCK_SEQUENCE_STYLE:
453                flow_style = False
454            return self.cached_SequenceStartEvent(anchor, tag, implicit,
455                    start_mark, end_mark, flow_style)
456        elif event.type == YAML_MAPPING_START_EVENT:
457            anchor = None
458            if event.data.mapping_start.anchor != NULL:
459                anchor = PyUnicode_DecodeUTF8(event.data.mapping_start.anchor,
460                        strlen(event.data.mapping_start.anchor), 'strict')
461            tag = None
462            if event.data.mapping_start.tag != NULL:
463                tag = PyUnicode_DecodeUTF8(event.data.mapping_start.tag,
464                        strlen(event.data.mapping_start.tag), 'strict')
465            implicit = (event.data.mapping_start.implicit == 1)
466            flow_style = None
467            if event.data.mapping_start.style == YAML_FLOW_SEQUENCE_STYLE:
468                flow_style = True
469            elif event.data.mapping_start.style == YAML_BLOCK_SEQUENCE_STYLE:
470                flow_style = False
471            return self.cached_MappingStartEvent(anchor, tag, implicit,
472                    start_mark, end_mark, flow_style)
473        elif event.type == YAML_SEQUENCE_END_EVENT:
474            return self.cached_SequenceEndEvent(start_mark, end_mark)
475        elif event.type == YAML_MAPPING_END_EVENT:
476            return self.cached_MappingEndEvent(start_mark, end_mark)
477        else:
478            raise RuntimeError("unknown event type")
479
480cdef int input_handler(void *data, char *buffer, int size, int *read) except 0:
481    cdef ScannerAndParser parser
482    parser = <ScannerAndParser>data
483    value = parser.stream.read(size)
484    if PyString_CheckExact(value) == 0:
485        raise TypeError("a string value is expected")
486    if PyString_GET_SIZE(value) > size:
487        raise ValueError("a string value it too long")
488    memcpy(buffer, PyString_AS_STRING(value), PyString_GET_SIZE(value))
489    read[0] = PyString_GET_SIZE(value)
490    return 1
491
492class Loader(ScannerAndParser,
493        yaml.composer.Composer,
494        yaml.constructor.Constructor,
495        yaml.resolver.Resolver):
496
497    def __init__(self, stream):
498        ScannerAndParser.__init__(self, stream)
499        yaml.composer.Composer.__init__(self)
500        yaml.constructor.Constructor.__init__(self)
501        yaml.resolver.Resolver.__init__(self)
502
503yaml.ExtLoader = Loader
504
Note: See TracBrowser for help on using the repository browser.