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

Revision 195, 7.5 KB checked in by xi, 8 years ago (diff)

Add pyrex-based bindings for the libyaml scanner.

RevLine 
[195]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
12cdef class Scanner:
13
14    cdef yaml_parser_t *parser
15    cdef int eof
16    cdef object stream
17
18    def __init__(self, stream):
19        cdef char *input
20        cdef int size
21        if hasattr(stream, 'read'):
22            stream = stream.read()
23        if PyUnicode_CheckExact(stream) != 0:
24            stream = stream.encode('utf-8')
25        if PyString_CheckExact(stream) == 0:
26            raise TypeError("a string or stream input is required")
27        self.parser = yaml_parser_new()
28        if self.parser == NULL:
29            raise MemoryError
30        yaml_parser_set_input_string(self.parser, PyString_AS_STRING(stream), PyString_GET_SIZE(stream))
31        self.eof = 0
32        self.stream = stream
33
34    def __dealloc__(self):
35        if self.parser != NULL:
36            yaml_parser_delete(self.parser)
37            self.parser = NULL
38
39    cdef object _convert(self, yaml_token_t *token):
40        if token == NULL:
41            if self.parser.error == YAML_MEMORY_ERROR:
42                raise MemoryError
43            elif self.parser.error == YAML_READER_ERROR:
44                raise yaml.reader.ReaderError("<input>",
45                        self.parser.problem_offset,
46                        self.parser.problem_value,
47                        '?', self.parser.problem)
48            elif self.parser.error == YAML_SCANNER_ERROR:
49                if self.parser.context != NULL:
50                    raise yaml.scanner.ScannerError(
51                            self.parser.context,
52                            yaml.Mark("<input>",
53                                self.parser.context_mark.index,
54                                self.parser.context_mark.line,
55                                self.parser.context_mark.column,
56                                None, None),
57                            self.parser.problem,
58                            yaml.Mark("<input>",
59                                self.parser.problem_mark.index,
60                                self.parser.problem_mark.line,
61                                self.parser.problem_mark.column,
62                                None, None))
63                else:
64                    raise yaml.scanner.ScannerError(None, None,
65                            self.parser.problem,
66                            yaml.Mark("<input>",
67                                self.parser.problem_mark.index,
68                                self.parser.problem_mark.line,
69                                self.parser.problem_mark.column,
70                                None, None))
71            else:
72                raise RuntimeError("neither error nor token produced")
73        start_mark = yaml.Mark("<input>",
74                token.start_mark.index,
75                token.start_mark.line,
76                token.start_mark.column,
77                None, None)
78        end_mark = yaml.Mark("<input>",
79                token.end_mark.index,
80                token.end_mark.line,
81                token.end_mark.column,
82                None, None)
83        if token.type == YAML_STREAM_START_TOKEN:
84            return yaml.StreamStartToken(start_mark, end_mark)
85        elif token.type == YAML_STREAM_END_TOKEN:
86            return yaml.StreamEndToken(start_mark, end_mark)
87        elif token.type == YAML_VERSION_DIRECTIVE_TOKEN:
88            return yaml.DirectiveToken('YAML',
89                    (token.data.version_directive.major,
90                        token.data.version_directive.minor),
91                    start_mark, end_mark)
92        elif token.type == YAML_TAG_DIRECTIVE_TOKEN:
93            return yaml.DirectiveToken('TAG',
94                    (token.data.tag_directive.handle,
95                        token.data.tag_directive.prefix),
96                    start_mark, end_mark)
97        elif token.type == YAML_DOCUMENT_START_TOKEN:
98            return yaml.DocumentStartToken(start_mark, end_mark)
99        elif token.type == YAML_DOCUMENT_END_TOKEN:
100            return yaml.DocumentEndToken(start_mark, end_mark)
101        elif token.type == YAML_BLOCK_SEQUENCE_START_TOKEN:
102            return yaml.BlockSequenceStartToken(start_mark, end_mark)
103        elif token.type == YAML_BLOCK_MAPPING_START_TOKEN:
104            return yaml.BlockMappingStartToken(start_mark, end_mark)
105        elif token.type == YAML_BLOCK_END_TOKEN:
106            return yaml.BlockEndToken(start_mark, end_mark)
107        elif token.type == YAML_FLOW_SEQUENCE_START_TOKEN:
108            return yaml.FlowSequenceStartToken(start_mark, end_mark)
109        elif token.type == YAML_FLOW_SEQUENCE_END_TOKEN:
110            return yaml.FlowSequenceEndToken(start_mark, end_mark)
111        elif token.type == YAML_FLOW_MAPPING_START_TOKEN:
112            return yaml.FlowMappingStartToken(start_mark, end_mark)
113        elif token.type == YAML_FLOW_MAPPING_END_TOKEN:
114            return yaml.FlowMappingEndToken(start_mark, end_mark)
115        elif token.type == YAML_BLOCK_ENTRY_TOKEN:
116            return yaml.BlockEntryToken(start_mark, end_mark)
117        elif token.type == YAML_FLOW_ENTRY_TOKEN:
118            return yaml.FlowEntryToken(start_mark, end_mark)
119        elif token.type == YAML_KEY_TOKEN:
120            return yaml.KeyToken(start_mark, end_mark)
121        elif token.type == YAML_VALUE_TOKEN:
122            return yaml.ValueToken(start_mark, end_mark)
123        elif token.type == YAML_ALIAS_TOKEN:
124            return yaml.AliasToken(token.data.anchor,
125                    start_mark, end_mark)
126        elif token.type == YAML_ANCHOR_TOKEN:
127            return yaml.AnchorToken(token.data.anchor,
128                    start_mark, end_mark)
129        elif token.type == YAML_TAG_TOKEN:
130            handle = token.data.tag.handle
131            if handle == '':
132                handle = None
133            return yaml.TagToken((handle, token.data.tag.suffix),
134                    start_mark, end_mark)
135        elif token.type == YAML_SCALAR_TOKEN:
136            value = PyString_FromStringAndSize(token.data.scalar.value, token.data.scalar.length)
137            return yaml.ScalarToken(unicode(value, 'utf-8'),
138                    bool(token.data.scalar.style == YAML_PLAIN_SCALAR_STYLE),
139                    start_mark, end_mark)
140        else:
141            raise RuntimeError("unknown token type")
142
143    def get_token(self):
144        cdef yaml_token_t *token
145        if self.eof != 0:
146            return None
147        token = yaml_parser_get_token(self.parser)
148        obj = self._convert(token)
149        if token.type == YAML_STREAM_END_TOKEN:
150            self.eof = 1
151        yaml_token_delete(token)
152        return obj
153
154    def peek_token(self):
155        cdef yaml_token_t *token
156        if self.eof != 0:
157            return None
158        token = yaml_parser_peek_token(self.parser)
159        return self._convert(token)
160
161    def check_token(self, *choices):
162        cdef yaml_token_t *token
163        if self.eof != 0:
164            return False
165        token = yaml_parser_peek_token(self.parser)
166        obj = self._convert(token)
167        if not choices:
168            return True
169        for choice in choices:
170            if isinstance(obj, choice):
171                return True
172        return False
173
174class Loader(Scanner,
175        yaml.parser.Parser,
176        yaml.composer.Composer,
177        yaml.constructor.Constructor,
178        yaml.resolver.Resolver):
179
180    def __init__(self, stream):
181        Scanner.__init__(self, stream)
182        yaml.parser.Parser.__init__(self)
183        yaml.composer.Composer.__init__(self)
184        yaml.constructor.Constructor.__init__(self)
185        yaml.resolver.Resolver.__init__(self)
186
187yaml.ExtLoader = Loader
188
Note: See TracBrowser for help on using the repository browser.