Add pyrex-based bindings for the libyaml scanner.
[pyyaml/python3.git] / ext / _yaml.pyx
blob40ce4ba6a6daacdde6a653a115dbbb148cc19cde
2 import yaml
4 def get_version_string():
5 return yaml_get_version_string()
7 def get_version():
8 cdef int major, minor, patch
9 yaml_get_version(&major, &minor, &patch)
10 return (major, minor, patch)
12 cdef class Scanner:
14 cdef yaml_parser_t *parser
15 cdef int eof
16 cdef object stream
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
34 def __dealloc__(self):
35 if self.parser != NULL:
36 yaml_parser_delete(self.parser)
37 self.parser = NULL
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")
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
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)
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
174 class Loader(Scanner,
175 yaml.parser.Parser,
176 yaml.composer.Composer,
177 yaml.constructor.Constructor,
178 yaml.resolver.Resolver):
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)
187 yaml.ExtLoader = Loader