source: branches/pyyaml3000/lib/yaml/parser.py @ 43

Revision 43, 10.1 KB checked in by xi, 9 years ago (diff)

Scanner is mostly completed. Need to write alias, tag, and scalar scanners.

Line 
1
2# Production rules:
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?)?
21
22# FIRST(rule) sets:
23# stream: {}
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 }
41
42class Parser:
43
44    def parse(self, source, data):
45        scanner = Scanner()
46        self.tokens = scanner.scan(source, data)
47        self.tokens.append('END')
48        documents = self.parse_stream()
49        if len(documents) == 1:
50            return documents[0]
51        return documents
52
53    def parse_stream(self):
54        documents = []
55        if self.tokens[0] not in ['DIRECTIVE', 'DOCUMENT_START', 'END']:
56            documents.append(self.parse_block_node())
57        while self.tokens[0] != 'END':
58            while self.tokens[0] == 'DIRECTIVE':
59                self.tokens.pop(0)
60            if self.tokens[0] != 'DOCUMENT_START':
61                self.error('DOCUMENT_START is expected')
62            self.tokens.pop(0)
63            if self.tokens[0] in ['DIRECTIVE', 'DOCUMENT_START', 'DOCUMENT_END', 'END']:
64                documents.append(None)
65            else:
66                documents.append(self.parse_block_node())
67            while self.tokens[0] == 'DOCUMENT_END':
68                self.tokens.pop(0)
69        if self.tokens[0] != 'END':
70            self.error("END is expected")
71        return tuple(documents)
72
73    def parse_block_node(self):
74        if self.tokens[0] == 'ALIAS':
75            self.tokens.pop(0)
76            return '*'
77        if self.tokens[0] == 'TAG':
78            self.tokens.pop(0)
79            if self.tokens[0] == 'ANCHOR':
80                self.tokens.pop(0)
81        elif self.tokens[0] == 'ANCHOR':
82            self.tokens.pop(0)
83            if self.tokens[0] == 'TAG':
84                self.tokens.pop(0)
85        return self.parse_block_content()
86
87    def parse_flow_node(self):
88        if self.tokens[0] == 'ALIAS':
89            self.tokens.pop(0)
90            return '*'
91        if self.tokens[0] == 'TAG':
92            self.tokens.pop(0)
93            if self.tokens[0] == 'ANCHOR':
94                self.tokens.pop(0)
95        elif self.tokens[0] == 'ANCHOR':
96            self.tokens.pop(0)
97            if self.tokens[0] == 'TAG':
98                self.tokens.pop(0)
99        return self.parse_flow_content()
100
101    def parse_block_node_or_indentless_sequence(self):
102        if self.tokens[0] == 'ALIAS':
103            self.tokens.pop(0)
104            return '*'
105        if self.tokens[0] == 'TAG':
106            self.tokens.pop(0)
107            if self.tokens[0] == 'ANCHOR':
108                self.tokens.pop(0)
109        elif self.tokens[0] == 'ANCHOR':
110            self.tokens.pop(0)
111            if self.tokens[0] == 'TAG':
112                self.tokens.pop(0)
113        if self.tokens[0] == 'ENTRY':
114            return self.parse_indentless_sequence(self)
115        return self.parse_block_content()
116
117    def parse_block_content(self):
118        if self.tokens[0] == 'SCALAR':
119            self.tokens.pop(0)
120            return True
121        elif self.tokens[0] == 'BLOCK_SEQ_START':
122            return self.parse_block_sequence()
123        elif self.tokens[0] == 'BLOCK_MAP_START':
124            return self.parse_block_mapping()
125        elif self.tokens[0] == 'FLOW_SEQ_START':
126            return self.parse_flow_sequence()
127        elif self.tokens[0] == 'FLOW_MAP_START':
128            return self.parse_flow_mapping()
129        else:
130            self.error('block content is expected')
131
132    def parse_flow_content(self):
133        if self.tokens[0] == 'SCALAR':
134            self.tokens.pop(0)
135            return True
136        elif self.tokens[0] == 'FLOW_SEQ_START':
137            return self.parse_flow_sequence()
138        elif self.tokens[0] == 'FLOW_MAP_START':
139            return self.parse_flow_mapping()
140        else:
141            self.error('flow content is expected')
142
143    def parse_block_sequence(self):
144        sequence = []
145        if self.tokens[0] != 'BLOCK_SEQ_START':
146            self.error('BLOCK_SEQ_START is expected')
147        self.tokens.pop(0)
148        while self.tokens[0] == 'ENTRY':
149            self.tokens.pop(0)
150            if self.tokens[0] not in ['ENTRY', 'BLOCK_END']:
151                sequence.append(self.parse_block_node())
152            else:
153                sequence.append(None)
154        if self.tokens[0] != 'BLOCK_END':
155            self.error('BLOCK_END is expected')
156        self.tokens.pop(0)
157        return sequence
158
159    def parse_indentless_sequence(self):
160        sequence = []
161        while self.tokens[0] == 'ENTRY':
162            self.tokens.pop(0)
163            if self.tokens[0] not in ['ENTRY']:
164                sequence.append(self.parse_block_node())
165            else:
166                sequence.append(None)
167        return sequence
168
169    def parse_block_mapping(self):
170        mapping = []
171        if self.tokens[0] != 'BLOCK_MAP_START':
172            self.error('BLOCK_MAP_START is expected')
173        self.tokens.pop(0)
174        while self.tokens[0] in ['KEY', 'VALUE']:
175            key = None
176            value = None
177            if self.tokens[0] == 'KEY':
178                self.tokens.pop(0)
179                if self.tokens[0] not in ['KEY', 'VALUE', 'BLOCK_END']:
180                    key = self.parse_block_node_or_indentless_sequence()
181            if self.tokens[0] == 'VALUE':
182                self.tokens.pop(0)
183                if self.tokens[0] not in ['KEY', 'VALUE', 'BLOCK_END']:
184                    value = self.parse_block_node_or_indentless_sequence()
185            mapping.append((key, value))
186        if self.tokens[0] != 'BLOCK_END':
187            self.error('BLOCK_END is expected')
188        self.tokens.pop(0)
189        return mapping
190
191    def parse_flow_sequence(self):
192        sequence = []
193        if self.tokens[0] != 'FLOW_SEQ_START':
194            self.error('FLOW_SEQ_START is expected')
195        self.tokens.pop(0)
196        while self.tokens[0] != 'FLOW_SEQ_END':
197            if self.tokens[0] == 'KEY':
198                self.tokens.pop(0)
199                key = None
200                value = None
201                if self.tokens[0] != 'VALUE':
202                    key = self.parse_flow_node()
203                if self.tokens[0] == 'VALUE':
204                    self.tokens.pop(0)
205                    if self.tokens[0] not in ['ENTRY', 'FLOW_SEQ_END']:
206                        value = self.parse_flow_node()
207                sequence.append([(key, value)])
208            else:
209                sequence.append(self.parse_flow_node())
210            if self.tokens[0] not in ['ENTRY', 'FLOW_SEQ_END']:
211                self.error("ENTRY or FLOW_SEQ_END is expected")
212            if self.tokens[0] == 'ENTRY':
213                self.tokens.pop(0)
214        if self.tokens[0] != 'FLOW_SEQ_END':
215            self.error('FLOW_SEQ_END is expected')
216        self.tokens.pop(0)
217        return sequence
218
219    def parse_flow_mapping(self):
220        mapping = []
221        if self.tokens[0] != 'FLOW_MAP_START':
222            self.error('FLOW_MAP_START is expected')
223        self.tokens.pop(0)
224        while self.tokens[0] != 'FLOW_MAP_END':
225            if self.tokens[0] == 'KEY':
226                self.tokens.pop(0)
227                key = None
228                value = None
229                if self.tokens[0] != 'VALUE':
230                    key = self.parse_flow_node()
231                if self.tokens[0] == 'VALUE':
232                    self.tokens.pop(0)
233                    if self.tokens[0] not in ['ENTRY', 'FLOW_MAP_END']:
234                        value = self.parse_flow_node()
235                mapping.append((key, value))
236            else:
237                mapping.append((self.parse_flow_node(), None))
238            if self.tokens[0] not in ['ENTRY', 'FLOW_MAP_END']:
239                self.error("ENTRY or FLOW_MAP_END is expected")
240            if self.tokens[0] == 'ENTRY':
241                self.tokens.pop(0)
242        if self.tokens[0] != 'FLOW_MAP_END':
243            self.error('FLOW_MAP_END is expected')
244        self.tokens.pop(0)
245        return mapping
246
247    def error(self, message):
248        raise Error(message+': '+str(self.tokens))
249
250
Note: See TracBrowser for help on using the repository browser.