3 # stream ::= implicit_document? explicit_document* END
4 # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END?
5 # implicit_document ::= block_node DOCUMENT-END?
6 # block_node ::= ALIAS | properties? block_content
7 # flow_node ::= ALIAS | properties? flow_content
8 # properties ::= TAG ANCHOR? | ANCHOR TAG?
9 # block_content ::= block_collection | flow_collection | SCALAR
10 # flow_content ::= flow_collection | SCALAR
11 # block_collection ::= block_sequence | block_mapping
12 # block_sequence ::= BLOCK-SEQUENCE-START (ENTRY block_node?)* BLOCK-END
13 # block_mapping ::= BLOCK-MAPPING_START ((KEY block_node_or_indentless_sequence?)? (VALUE block_node_or_indentless_sequence?)?)* BLOCK-END
14 # block_node_or_indentless_sequence ::= ALIAS | properties? (block_content | indentless_block_sequence)
15 # indentless_block_sequence ::= (ENTRY block_node?)+
16 # flow_collection ::= flow_sequence | flow_mapping
17 # flow_sequence ::= FLOW-SEQUENCE-START (flow_sequence_entry ENTRY)* flow_sequence_entry? FLOW-SEQUENCE-END
18 # flow_mapping ::= FLOW-MAPPING-START flow_mapping_entry ENTRY)* flow_mapping_entry? FLOW-MAPPING-END
19 # flow_sequence_entry ::= flow_node | KEY flow_node (VALUE flow_node?)?
20 # flow_mapping_entry ::= flow_node | KEY flow_node (VALUE flow_node?)?
24 # explicit_document: { DIRECTIVE DOCUMENT-START }
25 # implicit_document: block_node
26 # block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
27 # flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
28 # block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
29 # flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
30 # block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
31 # flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
32 # block_sequence: { BLOCK-SEQUENCE-START }
33 # block_mapping: { BLOCK-MAPPING-START }
34 # block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START ENTRY }
35 # indentless_sequence: { ENTRY }
36 # flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
37 # flow_sequence: { FLOW-SEQUENCE-START }
38 # flow_mapping: { FLOW-MAPPING-START }
39 # flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
40 # flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
42 from error
import YAMLError
45 class ParserError(YAMLError
):
51 for attribute
in ['anchor', 'tag', 'value']:
52 if hasattr(self
, attribute
):
53 args
.append(repr(getattr(self
, attribute
)))
54 return "%s(%s)" % (self
.__class
__.__name
__, ', '.join(args
))
56 class AliasNode(Node
):
57 def __init__(self
, anchor
):
60 class ScalarNode(Node
):
61 def __init__(self
, anchor
, tag
, value
):
66 class SequenceNode(Node
):
67 def __init__(self
, anchor
, tag
, value
):
72 class MappingNode(Node
):
73 def __init__(self
, anchor
, tag
, value
):
80 def __init__(self
, scanner
):
81 self
.scanner
= scanner
83 def is_token(self
, *choices
):
84 token
= self
.scanner
.peek_token()
85 for choice
in choices
:
86 if isinstance(token
, choices
):
91 return self
.scanner
.get_token()
94 return self
.parse_stream()
96 def parse_stream(self
):
98 if not self
.is_token(DirectiveToken
, DocumentStartToken
, EndToken
):
99 documents
.append(self
.parse_block_node())
100 while not self
.is_token(EndToken
):
101 while self
.is_token(DirectiveToken
):
103 if not self
.is_token(DocumentStartToken
):
104 self
.fail('DOCUMENT-START is expected')
106 if self
.is_token(DirectiveToken
,
107 DocumentStartToken
, DocumentEndToken
, EndToken
):
108 documents
.append(None)
110 documents
.append(self
.parse_block_node())
111 while self
.is_token(DocumentEndToken
):
113 if not self
.is_token(EndToken
):
114 self
.fail("END is expected")
117 def parse_block_node(self
):
118 return self
.parse_node(block
=True)
120 def parse_flow_node(self
):
121 return self
.parse_node()
123 def parse_block_node_or_indentless_sequence(self
):
124 return self
.parse_node(block
=True, indentless_sequence
=True)
126 def parse_node(self
, block
=False, indentless_sequence
=False):
127 if self
.is_token(AliasToken
):
128 token
= self
.get_token()
129 return AliasNode(token
.value
)
132 if self
.is_token(AnchorToken
):
133 anchor
= self
.get_token().value
134 if self
.is_token(TagToken
):
135 tag
= self
.get_token().value
136 elif self
.is_token(TagToken
):
137 tag
= self
.get_token().value
138 if self
.is_token(AnchorToken
):
139 anchor
= self
.get_token().value
140 if indentless_sequence
and self
.is_token(EntryToken
):
141 NodeClass
= SequenceNode
142 value
= self
.parse_indentless_sequence()
144 if self
.is_token(ScalarToken
):
145 NodeClass
= ScalarNode
146 elif self
.is_token(BlockSequenceStartToken
, FlowSequenceStartToken
):
147 NodeClass
= SequenceNode
148 elif self
.is_token(BlockMappingStartToken
, FlowMappingStartToken
):
149 NodeClass
= MappingNode
151 value
= self
.parse_block_content()
153 value
= self
.parse_flow_content()
154 return NodeClass(anchor
, tag
, value
)
156 def parse_block_content(self
):
157 if self
.is_token(ScalarToken
):
158 return self
.get_token().value
159 elif self
.is_token(BlockSequenceStartToken
):
160 return self
.parse_block_sequence()
161 elif self
.is_token(BlockMappingStartToken
):
162 return self
.parse_block_mapping()
163 elif self
.is_token(FlowSequenceStartToken
):
164 return self
.parse_flow_sequence()
165 elif self
.is_token(FlowMappingStartToken
):
166 return self
.parse_flow_mapping()
168 self
.fail('block content is expected')
170 def parse_flow_content(self
):
171 if self
.is_token(ScalarToken
):
172 return self
.get_token().value
173 elif self
.is_token(FlowSequenceStartToken
):
174 return self
.parse_flow_sequence()
175 elif self
.is_token(FlowMappingStartToken
):
176 return self
.parse_flow_mapping()
178 self
.fail('flow content is expected')
180 def parse_block_sequence(self
):
182 if not self
.is_token(BlockSequenceStartToken
):
183 self
.fail('BLOCK-SEQUENCE-START is expected')
185 while self
.is_token(EntryToken
):
187 if not self
.is_token(EntryToken
, BlockEndToken
):
188 sequence
.append(self
.parse_block_node())
190 sequence
.append(None)
191 if not self
.is_token(BlockEndToken
):
192 self
.fail('BLOCK-END is expected')
196 def parse_indentless_sequence(self
):
198 while self
.is_token(EntryToken
):
200 if not self
.is_token(EntryToken
):
201 sequence
.append(self
.parse_block_node())
203 sequence
.append(None)
206 def parse_block_mapping(self
):
208 if not self
.is_token(BlockMappingStartToken
):
209 self
.fail('BLOCK-MAPPING-START is expected')
211 while self
.is_token(KeyToken
, ValueToken
):
214 if self
.is_token(KeyToken
):
216 if not self
.is_token(KeyToken
, ValueToken
, BlockEndToken
):
217 key
= self
.parse_block_node_or_indentless_sequence()
218 if self
.is_token(ValueToken
):
220 if not self
.is_token(KeyToken
, ValueToken
, BlockEndToken
):
221 value
= self
.parse_block_node_or_indentless_sequence()
222 mapping
.append((key
, value
))
223 if not self
.is_token(BlockEndToken
):
224 self
.fail('BLOCK-END is expected')
228 def parse_flow_sequence(self
):
230 if not self
.is_token(FlowSequenceStartToken
):
231 self
.fail('FLOW-SEQUENCE-START is expected')
233 while not self
.is_token(FlowSequenceEndToken
):
234 if self
.is_token(KeyToken
):
238 if not self
.is_token(ValueToken
):
239 key
= self
.parse_flow_node()
240 if self
.is_token(ValueToken
):
242 if not self
.is_token(EntryToken
, FlowSequenceEndToken
):
243 value
= self
.parse_flow_node()
244 node
= MappingNode(None, None, [(key
, value
)])
245 sequence
.append(node
)
247 sequence
.append(self
.parse_flow_node())
248 if not self
.is_token(EntryToken
, FlowSequenceEndToken
):
249 self
.fail("ENTRY or FLOW-SEQUENCE-END are expected")
250 if self
.is_token(EntryToken
):
252 if not self
.is_token(FlowSequenceEndToken
):
253 self
.fail('FLOW-SEQUENCE-END is expected')
257 def parse_flow_mapping(self
):
259 if not self
.is_token(FlowMappingStartToken
):
260 self
.fail('FLOW-MAPPING-START is expected')
262 while not self
.is_token(FlowMappingEndToken
):
263 if self
.is_token(KeyToken
):
267 if not self
.is_token(ValueToken
):
268 key
= self
.parse_flow_node()
269 if self
.is_token(ValueToken
):
271 if not self
.is_token(EntryToken
, FlowMappingEndToken
):
272 value
= self
.parse_flow_node()
273 mapping
.append((key
, value
))
275 mapping
.append((self
.parse_flow_node(), None))
276 if not self
.is_token(EntryToken
, FlowMappingEndToken
):
277 self
.fail("ENTRY or FLOW-MAPPING-END are expected")
278 if self
.is_token(EntryToken
):
280 if not self
.is_token(FlowMappingEndToken
):
281 self
.fail('FLOW-MAPPING-END is expected')
285 def fail(self
, message
):
286 marker
= self
.scanner
.peek_token().start_marker
287 raise Error(message
+':\n'+marker
.get_snippet())