1 |
yakumo_izuru |
1.1 |
// |
2 |
|
|
// Copyright (c) 2011-2019 Canonical Ltd |
3 |
|
|
// Copyright (c) 2006-2010 Kirill Simonov |
4 |
|
|
// |
5 |
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of |
6 |
|
|
// this software and associated documentation files (the "Software"), to deal in |
7 |
|
|
// the Software without restriction, including without limitation the rights to |
8 |
|
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
9 |
|
|
// of the Software, and to permit persons to whom the Software is furnished to do |
10 |
|
|
// so, subject to the following conditions: |
11 |
|
|
// |
12 |
|
|
// The above copyright notice and this permission notice shall be included in all |
13 |
|
|
// copies or substantial portions of the Software. |
14 |
|
|
// |
15 |
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 |
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
18 |
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 |
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 |
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 |
|
|
// SOFTWARE. |
22 |
|
|
|
23 |
|
|
package yaml |
24 |
|
|
|
25 |
|
|
import ( |
26 |
|
|
"bytes" |
27 |
|
|
"fmt" |
28 |
|
|
) |
29 |
|
|
|
30 |
|
|
// Introduction |
31 |
|
|
// ************ |
32 |
|
|
// |
33 |
|
|
// The following notes assume that you are familiar with the YAML specification |
34 |
|
|
// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in |
35 |
|
|
// some cases we are less restrictive that it requires. |
36 |
|
|
// |
37 |
|
|
// The process of transforming a YAML stream into a sequence of events is |
38 |
|
|
// divided on two steps: Scanning and Parsing. |
39 |
|
|
// |
40 |
|
|
// The Scanner transforms the input stream into a sequence of tokens, while the |
41 |
|
|
// parser transform the sequence of tokens produced by the Scanner into a |
42 |
|
|
// sequence of parsing events. |
43 |
|
|
// |
44 |
|
|
// The Scanner is rather clever and complicated. The Parser, on the contrary, |
45 |
|
|
// is a straightforward implementation of a recursive-descendant parser (or, |
46 |
|
|
// LL(1) parser, as it is usually called). |
47 |
|
|
// |
48 |
|
|
// Actually there are two issues of Scanning that might be called "clever", the |
49 |
|
|
// rest is quite straightforward. The issues are "block collection start" and |
50 |
|
|
// "simple keys". Both issues are explained below in details. |
51 |
|
|
// |
52 |
|
|
// Here the Scanning step is explained and implemented. We start with the list |
53 |
|
|
// of all the tokens produced by the Scanner together with short descriptions. |
54 |
|
|
// |
55 |
|
|
// Now, tokens: |
56 |
|
|
// |
57 |
|
|
// STREAM-START(encoding) # The stream start. |
58 |
|
|
// STREAM-END # The stream end. |
59 |
|
|
// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. |
60 |
|
|
// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. |
61 |
|
|
// DOCUMENT-START # '---' |
62 |
|
|
// DOCUMENT-END # '...' |
63 |
|
|
// BLOCK-SEQUENCE-START # Indentation increase denoting a block |
64 |
|
|
// BLOCK-MAPPING-START # sequence or a block mapping. |
65 |
|
|
// BLOCK-END # Indentation decrease. |
66 |
|
|
// FLOW-SEQUENCE-START # '[' |
67 |
|
|
// FLOW-SEQUENCE-END # ']' |
68 |
|
|
// BLOCK-SEQUENCE-START # '{' |
69 |
|
|
// BLOCK-SEQUENCE-END # '}' |
70 |
|
|
// BLOCK-ENTRY # '-' |
71 |
|
|
// FLOW-ENTRY # ',' |
72 |
|
|
// KEY # '?' or nothing (simple keys). |
73 |
|
|
// VALUE # ':' |
74 |
|
|
// ALIAS(anchor) # '*anchor' |
75 |
|
|
// ANCHOR(anchor) # '&anchor' |
76 |
|
|
// TAG(handle,suffix) # '!handle!suffix' |
77 |
|
|
// SCALAR(value,style) # A scalar. |
78 |
|
|
// |
79 |
|
|
// The following two tokens are "virtual" tokens denoting the beginning and the |
80 |
|
|
// end of the stream: |
81 |
|
|
// |
82 |
|
|
// STREAM-START(encoding) |
83 |
|
|
// STREAM-END |
84 |
|
|
// |
85 |
|
|
// We pass the information about the input stream encoding with the |
86 |
|
|
// STREAM-START token. |
87 |
|
|
// |
88 |
|
|
// The next two tokens are responsible for tags: |
89 |
|
|
// |
90 |
|
|
// VERSION-DIRECTIVE(major,minor) |
91 |
|
|
// TAG-DIRECTIVE(handle,prefix) |
92 |
|
|
// |
93 |
|
|
// Example: |
94 |
|
|
// |
95 |
|
|
// %YAML 1.1 |
96 |
|
|
// %TAG ! !foo |
97 |
|
|
// %TAG !yaml! tag:yaml.org,2002: |
98 |
|
|
// --- |
99 |
|
|
// |
100 |
|
|
// The correspoding sequence of tokens: |
101 |
|
|
// |
102 |
|
|
// STREAM-START(utf-8) |
103 |
|
|
// VERSION-DIRECTIVE(1,1) |
104 |
|
|
// TAG-DIRECTIVE("!","!foo") |
105 |
|
|
// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") |
106 |
|
|
// DOCUMENT-START |
107 |
|
|
// STREAM-END |
108 |
|
|
// |
109 |
|
|
// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole |
110 |
|
|
// line. |
111 |
|
|
// |
112 |
|
|
// The document start and end indicators are represented by: |
113 |
|
|
// |
114 |
|
|
// DOCUMENT-START |
115 |
|
|
// DOCUMENT-END |
116 |
|
|
// |
117 |
|
|
// Note that if a YAML stream contains an implicit document (without '---' |
118 |
|
|
// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be |
119 |
|
|
// produced. |
120 |
|
|
// |
121 |
|
|
// In the following examples, we present whole documents together with the |
122 |
|
|
// produced tokens. |
123 |
|
|
// |
124 |
|
|
// 1. An implicit document: |
125 |
|
|
// |
126 |
|
|
// 'a scalar' |
127 |
|
|
// |
128 |
|
|
// Tokens: |
129 |
|
|
// |
130 |
|
|
// STREAM-START(utf-8) |
131 |
|
|
// SCALAR("a scalar",single-quoted) |
132 |
|
|
// STREAM-END |
133 |
|
|
// |
134 |
|
|
// 2. An explicit document: |
135 |
|
|
// |
136 |
|
|
// --- |
137 |
|
|
// 'a scalar' |
138 |
|
|
// ... |
139 |
|
|
// |
140 |
|
|
// Tokens: |
141 |
|
|
// |
142 |
|
|
// STREAM-START(utf-8) |
143 |
|
|
// DOCUMENT-START |
144 |
|
|
// SCALAR("a scalar",single-quoted) |
145 |
|
|
// DOCUMENT-END |
146 |
|
|
// STREAM-END |
147 |
|
|
// |
148 |
|
|
// 3. Several documents in a stream: |
149 |
|
|
// |
150 |
|
|
// 'a scalar' |
151 |
|
|
// --- |
152 |
|
|
// 'another scalar' |
153 |
|
|
// --- |
154 |
|
|
// 'yet another scalar' |
155 |
|
|
// |
156 |
|
|
// Tokens: |
157 |
|
|
// |
158 |
|
|
// STREAM-START(utf-8) |
159 |
|
|
// SCALAR("a scalar",single-quoted) |
160 |
|
|
// DOCUMENT-START |
161 |
|
|
// SCALAR("another scalar",single-quoted) |
162 |
|
|
// DOCUMENT-START |
163 |
|
|
// SCALAR("yet another scalar",single-quoted) |
164 |
|
|
// STREAM-END |
165 |
|
|
// |
166 |
|
|
// We have already introduced the SCALAR token above. The following tokens are |
167 |
|
|
// used to describe aliases, anchors, tag, and scalars: |
168 |
|
|
// |
169 |
|
|
// ALIAS(anchor) |
170 |
|
|
// ANCHOR(anchor) |
171 |
|
|
// TAG(handle,suffix) |
172 |
|
|
// SCALAR(value,style) |
173 |
|
|
// |
174 |
|
|
// The following series of examples illustrate the usage of these tokens: |
175 |
|
|
// |
176 |
|
|
// 1. A recursive sequence: |
177 |
|
|
// |
178 |
|
|
// &A [ *A ] |
179 |
|
|
// |
180 |
|
|
// Tokens: |
181 |
|
|
// |
182 |
|
|
// STREAM-START(utf-8) |
183 |
|
|
// ANCHOR("A") |
184 |
|
|
// FLOW-SEQUENCE-START |
185 |
|
|
// ALIAS("A") |
186 |
|
|
// FLOW-SEQUENCE-END |
187 |
|
|
// STREAM-END |
188 |
|
|
// |
189 |
|
|
// 2. A tagged scalar: |
190 |
|
|
// |
191 |
|
|
// !!float "3.14" # A good approximation. |
192 |
|
|
// |
193 |
|
|
// Tokens: |
194 |
|
|
// |
195 |
|
|
// STREAM-START(utf-8) |
196 |
|
|
// TAG("!!","float") |
197 |
|
|
// SCALAR("3.14",double-quoted) |
198 |
|
|
// STREAM-END |
199 |
|
|
// |
200 |
|
|
// 3. Various scalar styles: |
201 |
|
|
// |
202 |
|
|
// --- # Implicit empty plain scalars do not produce tokens. |
203 |
|
|
// --- a plain scalar |
204 |
|
|
// --- 'a single-quoted scalar' |
205 |
|
|
// --- "a double-quoted scalar" |
206 |
|
|
// --- |- |
207 |
|
|
// a literal scalar |
208 |
|
|
// --- >- |
209 |
|
|
// a folded |
210 |
|
|
// scalar |
211 |
|
|
// |
212 |
|
|
// Tokens: |
213 |
|
|
// |
214 |
|
|
// STREAM-START(utf-8) |
215 |
|
|
// DOCUMENT-START |
216 |
|
|
// DOCUMENT-START |
217 |
|
|
// SCALAR("a plain scalar",plain) |
218 |
|
|
// DOCUMENT-START |
219 |
|
|
// SCALAR("a single-quoted scalar",single-quoted) |
220 |
|
|
// DOCUMENT-START |
221 |
|
|
// SCALAR("a double-quoted scalar",double-quoted) |
222 |
|
|
// DOCUMENT-START |
223 |
|
|
// SCALAR("a literal scalar",literal) |
224 |
|
|
// DOCUMENT-START |
225 |
|
|
// SCALAR("a folded scalar",folded) |
226 |
|
|
// STREAM-END |
227 |
|
|
// |
228 |
|
|
// Now it's time to review collection-related tokens. We will start with |
229 |
|
|
// flow collections: |
230 |
|
|
// |
231 |
|
|
// FLOW-SEQUENCE-START |
232 |
|
|
// FLOW-SEQUENCE-END |
233 |
|
|
// FLOW-MAPPING-START |
234 |
|
|
// FLOW-MAPPING-END |
235 |
|
|
// FLOW-ENTRY |
236 |
|
|
// KEY |
237 |
|
|
// VALUE |
238 |
|
|
// |
239 |
|
|
// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and |
240 |
|
|
// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' |
241 |
|
|
// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the |
242 |
|
|
// indicators '?' and ':', which are used for denoting mapping keys and values, |
243 |
|
|
// are represented by the KEY and VALUE tokens. |
244 |
|
|
// |
245 |
|
|
// The following examples show flow collections: |
246 |
|
|
// |
247 |
|
|
// 1. A flow sequence: |
248 |
|
|
// |
249 |
|
|
// [item 1, item 2, item 3] |
250 |
|
|
// |
251 |
|
|
// Tokens: |
252 |
|
|
// |
253 |
|
|
// STREAM-START(utf-8) |
254 |
|
|
// FLOW-SEQUENCE-START |
255 |
|
|
// SCALAR("item 1",plain) |
256 |
|
|
// FLOW-ENTRY |
257 |
|
|
// SCALAR("item 2",plain) |
258 |
|
|
// FLOW-ENTRY |
259 |
|
|
// SCALAR("item 3",plain) |
260 |
|
|
// FLOW-SEQUENCE-END |
261 |
|
|
// STREAM-END |
262 |
|
|
// |
263 |
|
|
// 2. A flow mapping: |
264 |
|
|
// |
265 |
|
|
// { |
266 |
|
|
// a simple key: a value, # Note that the KEY token is produced. |
267 |
|
|
// ? a complex key: another value, |
268 |
|
|
// } |
269 |
|
|
// |
270 |
|
|
// Tokens: |
271 |
|
|
// |
272 |
|
|
// STREAM-START(utf-8) |
273 |
|
|
// FLOW-MAPPING-START |
274 |
|
|
// KEY |
275 |
|
|
// SCALAR("a simple key",plain) |
276 |
|
|
// VALUE |
277 |
|
|
// SCALAR("a value",plain) |
278 |
|
|
// FLOW-ENTRY |
279 |
|
|
// KEY |
280 |
|
|
// SCALAR("a complex key",plain) |
281 |
|
|
// VALUE |
282 |
|
|
// SCALAR("another value",plain) |
283 |
|
|
// FLOW-ENTRY |
284 |
|
|
// FLOW-MAPPING-END |
285 |
|
|
// STREAM-END |
286 |
|
|
// |
287 |
|
|
// A simple key is a key which is not denoted by the '?' indicator. Note that |
288 |
|
|
// the Scanner still produce the KEY token whenever it encounters a simple key. |
289 |
|
|
// |
290 |
|
|
// For scanning block collections, the following tokens are used (note that we |
291 |
|
|
// repeat KEY and VALUE here): |
292 |
|
|
// |
293 |
|
|
// BLOCK-SEQUENCE-START |
294 |
|
|
// BLOCK-MAPPING-START |
295 |
|
|
// BLOCK-END |
296 |
|
|
// BLOCK-ENTRY |
297 |
|
|
// KEY |
298 |
|
|
// VALUE |
299 |
|
|
// |
300 |
|
|
// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation |
301 |
|
|
// increase that precedes a block collection (cf. the INDENT token in Python). |
302 |
|
|
// The token BLOCK-END denote indentation decrease that ends a block collection |
303 |
|
|
// (cf. the DEDENT token in Python). However YAML has some syntax pecularities |
304 |
|
|
// that makes detections of these tokens more complex. |
305 |
|
|
// |
306 |
|
|
// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators |
307 |
|
|
// '-', '?', and ':' correspondingly. |
308 |
|
|
// |
309 |
|
|
// The following examples show how the tokens BLOCK-SEQUENCE-START, |
310 |
|
|
// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: |
311 |
|
|
// |
312 |
|
|
// 1. Block sequences: |
313 |
|
|
// |
314 |
|
|
// - item 1 |
315 |
|
|
// - item 2 |
316 |
|
|
// - |
317 |
|
|
// - item 3.1 |
318 |
|
|
// - item 3.2 |
319 |
|
|
// - |
320 |
|
|
// key 1: value 1 |
321 |
|
|
// key 2: value 2 |
322 |
|
|
// |
323 |
|
|
// Tokens: |
324 |
|
|
// |
325 |
|
|
// STREAM-START(utf-8) |
326 |
|
|
// BLOCK-SEQUENCE-START |
327 |
|
|
// BLOCK-ENTRY |
328 |
|
|
// SCALAR("item 1",plain) |
329 |
|
|
// BLOCK-ENTRY |
330 |
|
|
// SCALAR("item 2",plain) |
331 |
|
|
// BLOCK-ENTRY |
332 |
|
|
// BLOCK-SEQUENCE-START |
333 |
|
|
// BLOCK-ENTRY |
334 |
|
|
// SCALAR("item 3.1",plain) |
335 |
|
|
// BLOCK-ENTRY |
336 |
|
|
// SCALAR("item 3.2",plain) |
337 |
|
|
// BLOCK-END |
338 |
|
|
// BLOCK-ENTRY |
339 |
|
|
// BLOCK-MAPPING-START |
340 |
|
|
// KEY |
341 |
|
|
// SCALAR("key 1",plain) |
342 |
|
|
// VALUE |
343 |
|
|
// SCALAR("value 1",plain) |
344 |
|
|
// KEY |
345 |
|
|
// SCALAR("key 2",plain) |
346 |
|
|
// VALUE |
347 |
|
|
// SCALAR("value 2",plain) |
348 |
|
|
// BLOCK-END |
349 |
|
|
// BLOCK-END |
350 |
|
|
// STREAM-END |
351 |
|
|
// |
352 |
|
|
// 2. Block mappings: |
353 |
|
|
// |
354 |
|
|
// a simple key: a value # The KEY token is produced here. |
355 |
|
|
// ? a complex key |
356 |
|
|
// : another value |
357 |
|
|
// a mapping: |
358 |
|
|
// key 1: value 1 |
359 |
|
|
// key 2: value 2 |
360 |
|
|
// a sequence: |
361 |
|
|
// - item 1 |
362 |
|
|
// - item 2 |
363 |
|
|
// |
364 |
|
|
// Tokens: |
365 |
|
|
// |
366 |
|
|
// STREAM-START(utf-8) |
367 |
|
|
// BLOCK-MAPPING-START |
368 |
|
|
// KEY |
369 |
|
|
// SCALAR("a simple key",plain) |
370 |
|
|
// VALUE |
371 |
|
|
// SCALAR("a value",plain) |
372 |
|
|
// KEY |
373 |
|
|
// SCALAR("a complex key",plain) |
374 |
|
|
// VALUE |
375 |
|
|
// SCALAR("another value",plain) |
376 |
|
|
// KEY |
377 |
|
|
// SCALAR("a mapping",plain) |
378 |
|
|
// BLOCK-MAPPING-START |
379 |
|
|
// KEY |
380 |
|
|
// SCALAR("key 1",plain) |
381 |
|
|
// VALUE |
382 |
|
|
// SCALAR("value 1",plain) |
383 |
|
|
// KEY |
384 |
|
|
// SCALAR("key 2",plain) |
385 |
|
|
// VALUE |
386 |
|
|
// SCALAR("value 2",plain) |
387 |
|
|
// BLOCK-END |
388 |
|
|
// KEY |
389 |
|
|
// SCALAR("a sequence",plain) |
390 |
|
|
// VALUE |
391 |
|
|
// BLOCK-SEQUENCE-START |
392 |
|
|
// BLOCK-ENTRY |
393 |
|
|
// SCALAR("item 1",plain) |
394 |
|
|
// BLOCK-ENTRY |
395 |
|
|
// SCALAR("item 2",plain) |
396 |
|
|
// BLOCK-END |
397 |
|
|
// BLOCK-END |
398 |
|
|
// STREAM-END |
399 |
|
|
// |
400 |
|
|
// YAML does not always require to start a new block collection from a new |
401 |
|
|
// line. If the current line contains only '-', '?', and ':' indicators, a new |
402 |
|
|
// block collection may start at the current line. The following examples |
403 |
|
|
// illustrate this case: |
404 |
|
|
// |
405 |
|
|
// 1. Collections in a sequence: |
406 |
|
|
// |
407 |
|
|
// - - item 1 |
408 |
|
|
// - item 2 |
409 |
|
|
// - key 1: value 1 |
410 |
|
|
// key 2: value 2 |
411 |
|
|
// - ? complex key |
412 |
|
|
// : complex value |
413 |
|
|
// |
414 |
|
|
// Tokens: |
415 |
|
|
// |
416 |
|
|
// STREAM-START(utf-8) |
417 |
|
|
// BLOCK-SEQUENCE-START |
418 |
|
|
// BLOCK-ENTRY |
419 |
|
|
// BLOCK-SEQUENCE-START |
420 |
|
|
// BLOCK-ENTRY |
421 |
|
|
// SCALAR("item 1",plain) |
422 |
|
|
// BLOCK-ENTRY |
423 |
|
|
// SCALAR("item 2",plain) |
424 |
|
|
// BLOCK-END |
425 |
|
|
// BLOCK-ENTRY |
426 |
|
|
// BLOCK-MAPPING-START |
427 |
|
|
// KEY |
428 |
|
|
// SCALAR("key 1",plain) |
429 |
|
|
// VALUE |
430 |
|
|
// SCALAR("value 1",plain) |
431 |
|
|
// KEY |
432 |
|
|
// SCALAR("key 2",plain) |
433 |
|
|
// VALUE |
434 |
|
|
// SCALAR("value 2",plain) |
435 |
|
|
// BLOCK-END |
436 |
|
|
// BLOCK-ENTRY |
437 |
|
|
// BLOCK-MAPPING-START |
438 |
|
|
// KEY |
439 |
|
|
// SCALAR("complex key") |
440 |
|
|
// VALUE |
441 |
|
|
// SCALAR("complex value") |
442 |
|
|
// BLOCK-END |
443 |
|
|
// BLOCK-END |
444 |
|
|
// STREAM-END |
445 |
|
|
// |
446 |
|
|
// 2. Collections in a mapping: |
447 |
|
|
// |
448 |
|
|
// ? a sequence |
449 |
|
|
// : - item 1 |
450 |
|
|
// - item 2 |
451 |
|
|
// ? a mapping |
452 |
|
|
// : key 1: value 1 |
453 |
|
|
// key 2: value 2 |
454 |
|
|
// |
455 |
|
|
// Tokens: |
456 |
|
|
// |
457 |
|
|
// STREAM-START(utf-8) |
458 |
|
|
// BLOCK-MAPPING-START |
459 |
|
|
// KEY |
460 |
|
|
// SCALAR("a sequence",plain) |
461 |
|
|
// VALUE |
462 |
|
|
// BLOCK-SEQUENCE-START |
463 |
|
|
// BLOCK-ENTRY |
464 |
|
|
// SCALAR("item 1",plain) |
465 |
|
|
// BLOCK-ENTRY |
466 |
|
|
// SCALAR("item 2",plain) |
467 |
|
|
// BLOCK-END |
468 |
|
|
// KEY |
469 |
|
|
// SCALAR("a mapping",plain) |
470 |
|
|
// VALUE |
471 |
|
|
// BLOCK-MAPPING-START |
472 |
|
|
// KEY |
473 |
|
|
// SCALAR("key 1",plain) |
474 |
|
|
// VALUE |
475 |
|
|
// SCALAR("value 1",plain) |
476 |
|
|
// KEY |
477 |
|
|
// SCALAR("key 2",plain) |
478 |
|
|
// VALUE |
479 |
|
|
// SCALAR("value 2",plain) |
480 |
|
|
// BLOCK-END |
481 |
|
|
// BLOCK-END |
482 |
|
|
// STREAM-END |
483 |
|
|
// |
484 |
|
|
// YAML also permits non-indented sequences if they are included into a block |
485 |
|
|
// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: |
486 |
|
|
// |
487 |
|
|
// key: |
488 |
|
|
// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. |
489 |
|
|
// - item 2 |
490 |
|
|
// |
491 |
|
|
// Tokens: |
492 |
|
|
// |
493 |
|
|
// STREAM-START(utf-8) |
494 |
|
|
// BLOCK-MAPPING-START |
495 |
|
|
// KEY |
496 |
|
|
// SCALAR("key",plain) |
497 |
|
|
// VALUE |
498 |
|
|
// BLOCK-ENTRY |
499 |
|
|
// SCALAR("item 1",plain) |
500 |
|
|
// BLOCK-ENTRY |
501 |
|
|
// SCALAR("item 2",plain) |
502 |
|
|
// BLOCK-END |
503 |
|
|
// |
504 |
|
|
|
505 |
|
|
// Ensure that the buffer contains the required number of characters. |
506 |
|
|
// Return true on success, false on failure (reader error or memory error). |
507 |
|
|
func cache(parser *yaml_parser_t, length int) bool { |
508 |
|
|
// [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) |
509 |
|
|
return parser.unread >= length || yaml_parser_update_buffer(parser, length) |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
// Advance the buffer pointer. |
513 |
|
|
func skip(parser *yaml_parser_t) { |
514 |
|
|
if !is_blank(parser.buffer, parser.buffer_pos) { |
515 |
|
|
parser.newlines = 0 |
516 |
|
|
} |
517 |
|
|
parser.mark.index++ |
518 |
|
|
parser.mark.column++ |
519 |
|
|
parser.unread-- |
520 |
|
|
parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) |
521 |
|
|
} |
522 |
|
|
|
523 |
|
|
func skip_line(parser *yaml_parser_t) { |
524 |
|
|
if is_crlf(parser.buffer, parser.buffer_pos) { |
525 |
|
|
parser.mark.index += 2 |
526 |
|
|
parser.mark.column = 0 |
527 |
|
|
parser.mark.line++ |
528 |
|
|
parser.unread -= 2 |
529 |
|
|
parser.buffer_pos += 2 |
530 |
|
|
parser.newlines++ |
531 |
|
|
} else if is_break(parser.buffer, parser.buffer_pos) { |
532 |
|
|
parser.mark.index++ |
533 |
|
|
parser.mark.column = 0 |
534 |
|
|
parser.mark.line++ |
535 |
|
|
parser.unread-- |
536 |
|
|
parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) |
537 |
|
|
parser.newlines++ |
538 |
|
|
} |
539 |
|
|
} |
540 |
|
|
|
541 |
|
|
// Copy a character to a string buffer and advance pointers. |
542 |
|
|
func read(parser *yaml_parser_t, s []byte) []byte { |
543 |
|
|
if !is_blank(parser.buffer, parser.buffer_pos) { |
544 |
|
|
parser.newlines = 0 |
545 |
|
|
} |
546 |
|
|
w := width(parser.buffer[parser.buffer_pos]) |
547 |
|
|
if w == 0 { |
548 |
|
|
panic("invalid character sequence") |
549 |
|
|
} |
550 |
|
|
if len(s) == 0 { |
551 |
|
|
s = make([]byte, 0, 32) |
552 |
|
|
} |
553 |
|
|
if w == 1 && len(s)+w <= cap(s) { |
554 |
|
|
s = s[:len(s)+1] |
555 |
|
|
s[len(s)-1] = parser.buffer[parser.buffer_pos] |
556 |
|
|
parser.buffer_pos++ |
557 |
|
|
} else { |
558 |
|
|
s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) |
559 |
|
|
parser.buffer_pos += w |
560 |
|
|
} |
561 |
|
|
parser.mark.index++ |
562 |
|
|
parser.mark.column++ |
563 |
|
|
parser.unread-- |
564 |
|
|
return s |
565 |
|
|
} |
566 |
|
|
|
567 |
|
|
// Copy a line break character to a string buffer and advance pointers. |
568 |
|
|
func read_line(parser *yaml_parser_t, s []byte) []byte { |
569 |
|
|
buf := parser.buffer |
570 |
|
|
pos := parser.buffer_pos |
571 |
|
|
switch { |
572 |
|
|
case buf[pos] == '\r' && buf[pos+1] == '\n': |
573 |
|
|
// CR LF . LF |
574 |
|
|
s = append(s, '\n') |
575 |
|
|
parser.buffer_pos += 2 |
576 |
|
|
parser.mark.index++ |
577 |
|
|
parser.unread-- |
578 |
|
|
case buf[pos] == '\r' || buf[pos] == '\n': |
579 |
|
|
// CR|LF . LF |
580 |
|
|
s = append(s, '\n') |
581 |
|
|
parser.buffer_pos += 1 |
582 |
|
|
case buf[pos] == '\xC2' && buf[pos+1] == '\x85': |
583 |
|
|
// NEL . LF |
584 |
|
|
s = append(s, '\n') |
585 |
|
|
parser.buffer_pos += 2 |
586 |
|
|
case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): |
587 |
|
|
// LS|PS . LS|PS |
588 |
|
|
s = append(s, buf[parser.buffer_pos:pos+3]...) |
589 |
|
|
parser.buffer_pos += 3 |
590 |
|
|
default: |
591 |
|
|
return s |
592 |
|
|
} |
593 |
|
|
parser.mark.index++ |
594 |
|
|
parser.mark.column = 0 |
595 |
|
|
parser.mark.line++ |
596 |
|
|
parser.unread-- |
597 |
|
|
parser.newlines++ |
598 |
|
|
return s |
599 |
|
|
} |
600 |
|
|
|
601 |
|
|
// Get the next token. |
602 |
|
|
func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { |
603 |
|
|
// Erase the token object. |
604 |
|
|
*token = yaml_token_t{} // [Go] Is this necessary? |
605 |
|
|
|
606 |
|
|
// No tokens after STREAM-END or error. |
607 |
|
|
if parser.stream_end_produced || parser.error != yaml_NO_ERROR { |
608 |
|
|
return true |
609 |
|
|
} |
610 |
|
|
|
611 |
|
|
// Ensure that the tokens queue contains enough tokens. |
612 |
|
|
if !parser.token_available { |
613 |
|
|
if !yaml_parser_fetch_more_tokens(parser) { |
614 |
|
|
return false |
615 |
|
|
} |
616 |
|
|
} |
617 |
|
|
|
618 |
|
|
// Fetch the next token from the queue. |
619 |
|
|
*token = parser.tokens[parser.tokens_head] |
620 |
|
|
parser.tokens_head++ |
621 |
|
|
parser.tokens_parsed++ |
622 |
|
|
parser.token_available = false |
623 |
|
|
|
624 |
|
|
if token.typ == yaml_STREAM_END_TOKEN { |
625 |
|
|
parser.stream_end_produced = true |
626 |
|
|
} |
627 |
|
|
return true |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
// Set the scanner error and return false. |
631 |
|
|
func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { |
632 |
|
|
parser.error = yaml_SCANNER_ERROR |
633 |
|
|
parser.context = context |
634 |
|
|
parser.context_mark = context_mark |
635 |
|
|
parser.problem = problem |
636 |
|
|
parser.problem_mark = parser.mark |
637 |
|
|
return false |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { |
641 |
|
|
context := "while parsing a tag" |
642 |
|
|
if directive { |
643 |
|
|
context = "while parsing a %TAG directive" |
644 |
|
|
} |
645 |
|
|
return yaml_parser_set_scanner_error(parser, context, context_mark, problem) |
646 |
|
|
} |
647 |
|
|
|
648 |
|
|
func trace(args ...interface{}) func() { |
649 |
|
|
pargs := append([]interface{}{"+++"}, args...) |
650 |
|
|
fmt.Println(pargs...) |
651 |
|
|
pargs = append([]interface{}{"---"}, args...) |
652 |
|
|
return func() { fmt.Println(pargs...) } |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
// Ensure that the tokens queue contains at least one token which can be |
656 |
|
|
// returned to the Parser. |
657 |
|
|
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { |
658 |
|
|
// While we need more tokens to fetch, do it. |
659 |
|
|
for { |
660 |
|
|
// [Go] The comment parsing logic requires a lookahead of two tokens |
661 |
|
|
// so that foot comments may be parsed in time of associating them |
662 |
|
|
// with the tokens that are parsed before them, and also for line |
663 |
|
|
// comments to be transformed into head comments in some edge cases. |
664 |
|
|
if parser.tokens_head < len(parser.tokens)-2 { |
665 |
|
|
// If a potential simple key is at the head position, we need to fetch |
666 |
|
|
// the next token to disambiguate it. |
667 |
|
|
head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] |
668 |
|
|
if !ok { |
669 |
|
|
break |
670 |
|
|
} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { |
671 |
|
|
return false |
672 |
|
|
} else if !valid { |
673 |
|
|
break |
674 |
|
|
} |
675 |
|
|
} |
676 |
|
|
// Fetch the next token. |
677 |
|
|
if !yaml_parser_fetch_next_token(parser) { |
678 |
|
|
return false |
679 |
|
|
} |
680 |
|
|
} |
681 |
|
|
|
682 |
|
|
parser.token_available = true |
683 |
|
|
return true |
684 |
|
|
} |
685 |
|
|
|
686 |
|
|
// The dispatcher for token fetchers. |
687 |
|
|
func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) { |
688 |
|
|
// Ensure that the buffer is initialized. |
689 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
690 |
|
|
return false |
691 |
|
|
} |
692 |
|
|
|
693 |
|
|
// Check if we just started scanning. Fetch STREAM-START then. |
694 |
|
|
if !parser.stream_start_produced { |
695 |
|
|
return yaml_parser_fetch_stream_start(parser) |
696 |
|
|
} |
697 |
|
|
|
698 |
|
|
scan_mark := parser.mark |
699 |
|
|
|
700 |
|
|
// Eat whitespaces and comments until we reach the next token. |
701 |
|
|
if !yaml_parser_scan_to_next_token(parser) { |
702 |
|
|
return false |
703 |
|
|
} |
704 |
|
|
|
705 |
|
|
// [Go] While unrolling indents, transform the head comments of prior |
706 |
|
|
// indentation levels observed after scan_start into foot comments at |
707 |
|
|
// the respective indexes. |
708 |
|
|
|
709 |
|
|
// Check the indentation level against the current column. |
710 |
|
|
if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) { |
711 |
|
|
return false |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
// Ensure that the buffer contains at least 4 characters. 4 is the length |
715 |
|
|
// of the longest indicators ('--- ' and '... '). |
716 |
|
|
if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { |
717 |
|
|
return false |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
// Is it the end of the stream? |
721 |
|
|
if is_z(parser.buffer, parser.buffer_pos) { |
722 |
|
|
return yaml_parser_fetch_stream_end(parser) |
723 |
|
|
} |
724 |
|
|
|
725 |
|
|
// Is it a directive? |
726 |
|
|
if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { |
727 |
|
|
return yaml_parser_fetch_directive(parser) |
728 |
|
|
} |
729 |
|
|
|
730 |
|
|
buf := parser.buffer |
731 |
|
|
pos := parser.buffer_pos |
732 |
|
|
|
733 |
|
|
// Is it the document start indicator? |
734 |
|
|
if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { |
735 |
|
|
return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) |
736 |
|
|
} |
737 |
|
|
|
738 |
|
|
// Is it the document end indicator? |
739 |
|
|
if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { |
740 |
|
|
return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) |
741 |
|
|
} |
742 |
|
|
|
743 |
|
|
comment_mark := parser.mark |
744 |
|
|
if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') { |
745 |
|
|
// Associate any following comments with the prior token. |
746 |
|
|
comment_mark = parser.tokens[len(parser.tokens)-1].start_mark |
747 |
|
|
} |
748 |
|
|
defer func() { |
749 |
|
|
if !ok { |
750 |
|
|
return |
751 |
|
|
} |
752 |
|
|
if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN { |
753 |
|
|
// Sequence indicators alone have no line comments. It becomes |
754 |
|
|
// a head comment for whatever follows. |
755 |
|
|
return |
756 |
|
|
} |
757 |
|
|
if !yaml_parser_scan_line_comment(parser, comment_mark) { |
758 |
|
|
ok = false |
759 |
|
|
return |
760 |
|
|
} |
761 |
|
|
}() |
762 |
|
|
|
763 |
|
|
// Is it the flow sequence start indicator? |
764 |
|
|
if buf[pos] == '[' { |
765 |
|
|
return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) |
766 |
|
|
} |
767 |
|
|
|
768 |
|
|
// Is it the flow mapping start indicator? |
769 |
|
|
if parser.buffer[parser.buffer_pos] == '{' { |
770 |
|
|
return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) |
771 |
|
|
} |
772 |
|
|
|
773 |
|
|
// Is it the flow sequence end indicator? |
774 |
|
|
if parser.buffer[parser.buffer_pos] == ']' { |
775 |
|
|
return yaml_parser_fetch_flow_collection_end(parser, |
776 |
|
|
yaml_FLOW_SEQUENCE_END_TOKEN) |
777 |
|
|
} |
778 |
|
|
|
779 |
|
|
// Is it the flow mapping end indicator? |
780 |
|
|
if parser.buffer[parser.buffer_pos] == '}' { |
781 |
|
|
return yaml_parser_fetch_flow_collection_end(parser, |
782 |
|
|
yaml_FLOW_MAPPING_END_TOKEN) |
783 |
|
|
} |
784 |
|
|
|
785 |
|
|
// Is it the flow entry indicator? |
786 |
|
|
if parser.buffer[parser.buffer_pos] == ',' { |
787 |
|
|
return yaml_parser_fetch_flow_entry(parser) |
788 |
|
|
} |
789 |
|
|
|
790 |
|
|
// Is it the block entry indicator? |
791 |
|
|
if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { |
792 |
|
|
return yaml_parser_fetch_block_entry(parser) |
793 |
|
|
} |
794 |
|
|
|
795 |
|
|
// Is it the key indicator? |
796 |
|
|
if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { |
797 |
|
|
return yaml_parser_fetch_key(parser) |
798 |
|
|
} |
799 |
|
|
|
800 |
|
|
// Is it the value indicator? |
801 |
|
|
if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { |
802 |
|
|
return yaml_parser_fetch_value(parser) |
803 |
|
|
} |
804 |
|
|
|
805 |
|
|
// Is it an alias? |
806 |
|
|
if parser.buffer[parser.buffer_pos] == '*' { |
807 |
|
|
return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) |
808 |
|
|
} |
809 |
|
|
|
810 |
|
|
// Is it an anchor? |
811 |
|
|
if parser.buffer[parser.buffer_pos] == '&' { |
812 |
|
|
return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) |
813 |
|
|
} |
814 |
|
|
|
815 |
|
|
// Is it a tag? |
816 |
|
|
if parser.buffer[parser.buffer_pos] == '!' { |
817 |
|
|
return yaml_parser_fetch_tag(parser) |
818 |
|
|
} |
819 |
|
|
|
820 |
|
|
// Is it a literal scalar? |
821 |
|
|
if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { |
822 |
|
|
return yaml_parser_fetch_block_scalar(parser, true) |
823 |
|
|
} |
824 |
|
|
|
825 |
|
|
// Is it a folded scalar? |
826 |
|
|
if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { |
827 |
|
|
return yaml_parser_fetch_block_scalar(parser, false) |
828 |
|
|
} |
829 |
|
|
|
830 |
|
|
// Is it a single-quoted scalar? |
831 |
|
|
if parser.buffer[parser.buffer_pos] == '\'' { |
832 |
|
|
return yaml_parser_fetch_flow_scalar(parser, true) |
833 |
|
|
} |
834 |
|
|
|
835 |
|
|
// Is it a double-quoted scalar? |
836 |
|
|
if parser.buffer[parser.buffer_pos] == '"' { |
837 |
|
|
return yaml_parser_fetch_flow_scalar(parser, false) |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
// Is it a plain scalar? |
841 |
|
|
// |
842 |
|
|
// A plain scalar may start with any non-blank characters except |
843 |
|
|
// |
844 |
|
|
// '-', '?', ':', ',', '[', ']', '{', '}', |
845 |
|
|
// '#', '&', '*', '!', '|', '>', '\'', '\"', |
846 |
|
|
// '%', '@', '`'. |
847 |
|
|
// |
848 |
|
|
// In the block context (and, for the '-' indicator, in the flow context |
849 |
|
|
// too), it may also start with the characters |
850 |
|
|
// |
851 |
|
|
// '-', '?', ':' |
852 |
|
|
// |
853 |
|
|
// if it is followed by a non-space character. |
854 |
|
|
// |
855 |
|
|
// The last rule is more restrictive than the specification requires. |
856 |
|
|
// [Go] TODO Make this logic more reasonable. |
857 |
|
|
//switch parser.buffer[parser.buffer_pos] { |
858 |
|
|
//case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': |
859 |
|
|
//} |
860 |
|
|
if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || |
861 |
|
|
parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || |
862 |
|
|
parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || |
863 |
|
|
parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || |
864 |
|
|
parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || |
865 |
|
|
parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || |
866 |
|
|
parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || |
867 |
|
|
parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || |
868 |
|
|
parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || |
869 |
|
|
parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || |
870 |
|
|
(parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || |
871 |
|
|
(parser.flow_level == 0 && |
872 |
|
|
(parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && |
873 |
|
|
!is_blankz(parser.buffer, parser.buffer_pos+1)) { |
874 |
|
|
return yaml_parser_fetch_plain_scalar(parser) |
875 |
|
|
} |
876 |
|
|
|
877 |
|
|
// If we don't determine the token type so far, it is an error. |
878 |
|
|
return yaml_parser_set_scanner_error(parser, |
879 |
|
|
"while scanning for the next token", parser.mark, |
880 |
|
|
"found character that cannot start any token") |
881 |
|
|
} |
882 |
|
|
|
883 |
|
|
func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { |
884 |
|
|
if !simple_key.possible { |
885 |
|
|
return false, true |
886 |
|
|
} |
887 |
|
|
|
888 |
|
|
// The 1.2 specification says: |
889 |
|
|
// |
890 |
|
|
// "If the ? indicator is omitted, parsing needs to see past the |
891 |
|
|
// implicit key to recognize it as such. To limit the amount of |
892 |
|
|
// lookahead required, the “:” indicator must appear at most 1024 |
893 |
|
|
// Unicode characters beyond the start of the key. In addition, the key |
894 |
|
|
// is restricted to a single line." |
895 |
|
|
// |
896 |
|
|
if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { |
897 |
|
|
// Check if the potential simple key to be removed is required. |
898 |
|
|
if simple_key.required { |
899 |
|
|
return false, yaml_parser_set_scanner_error(parser, |
900 |
|
|
"while scanning a simple key", simple_key.mark, |
901 |
|
|
"could not find expected ':'") |
902 |
|
|
} |
903 |
|
|
simple_key.possible = false |
904 |
|
|
return false, true |
905 |
|
|
} |
906 |
|
|
return true, true |
907 |
|
|
} |
908 |
|
|
|
909 |
|
|
// Check if a simple key may start at the current position and add it if |
910 |
|
|
// needed. |
911 |
|
|
func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { |
912 |
|
|
// A simple key is required at the current position if the scanner is in |
913 |
|
|
// the block context and the current column coincides with the indentation |
914 |
|
|
// level. |
915 |
|
|
|
916 |
|
|
required := parser.flow_level == 0 && parser.indent == parser.mark.column |
917 |
|
|
|
918 |
|
|
// |
919 |
|
|
// If the current position may start a simple key, save it. |
920 |
|
|
// |
921 |
|
|
if parser.simple_key_allowed { |
922 |
|
|
simple_key := yaml_simple_key_t{ |
923 |
|
|
possible: true, |
924 |
|
|
required: required, |
925 |
|
|
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), |
926 |
|
|
mark: parser.mark, |
927 |
|
|
} |
928 |
|
|
|
929 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
930 |
|
|
return false |
931 |
|
|
} |
932 |
|
|
parser.simple_keys[len(parser.simple_keys)-1] = simple_key |
933 |
|
|
parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 |
934 |
|
|
} |
935 |
|
|
return true |
936 |
|
|
} |
937 |
|
|
|
938 |
|
|
// Remove a potential simple key at the current flow level. |
939 |
|
|
func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { |
940 |
|
|
i := len(parser.simple_keys) - 1 |
941 |
|
|
if parser.simple_keys[i].possible { |
942 |
|
|
// If the key is required, it is an error. |
943 |
|
|
if parser.simple_keys[i].required { |
944 |
|
|
return yaml_parser_set_scanner_error(parser, |
945 |
|
|
"while scanning a simple key", parser.simple_keys[i].mark, |
946 |
|
|
"could not find expected ':'") |
947 |
|
|
} |
948 |
|
|
// Remove the key from the stack. |
949 |
|
|
parser.simple_keys[i].possible = false |
950 |
|
|
delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) |
951 |
|
|
} |
952 |
|
|
return true |
953 |
|
|
} |
954 |
|
|
|
955 |
|
|
// max_flow_level limits the flow_level |
956 |
|
|
const max_flow_level = 10000 |
957 |
|
|
|
958 |
|
|
// Increase the flow level and resize the simple key list if needed. |
959 |
|
|
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { |
960 |
|
|
// Reset the simple key on the next level. |
961 |
|
|
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ |
962 |
|
|
possible: false, |
963 |
|
|
required: false, |
964 |
|
|
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), |
965 |
|
|
mark: parser.mark, |
966 |
|
|
}) |
967 |
|
|
|
968 |
|
|
// Increase the flow level. |
969 |
|
|
parser.flow_level++ |
970 |
|
|
if parser.flow_level > max_flow_level { |
971 |
|
|
return yaml_parser_set_scanner_error(parser, |
972 |
|
|
"while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark, |
973 |
|
|
fmt.Sprintf("exceeded max depth of %d", max_flow_level)) |
974 |
|
|
} |
975 |
|
|
return true |
976 |
|
|
} |
977 |
|
|
|
978 |
|
|
// Decrease the flow level. |
979 |
|
|
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { |
980 |
|
|
if parser.flow_level > 0 { |
981 |
|
|
parser.flow_level-- |
982 |
|
|
last := len(parser.simple_keys) - 1 |
983 |
|
|
delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) |
984 |
|
|
parser.simple_keys = parser.simple_keys[:last] |
985 |
|
|
} |
986 |
|
|
return true |
987 |
|
|
} |
988 |
|
|
|
989 |
|
|
// max_indents limits the indents stack size |
990 |
|
|
const max_indents = 10000 |
991 |
|
|
|
992 |
|
|
// Push the current indentation level to the stack and set the new level |
993 |
|
|
// the current column is greater than the indentation level. In this case, |
994 |
|
|
// append or insert the specified token into the token queue. |
995 |
|
|
func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { |
996 |
|
|
// In the flow context, do nothing. |
997 |
|
|
if parser.flow_level > 0 { |
998 |
|
|
return true |
999 |
|
|
} |
1000 |
|
|
|
1001 |
|
|
if parser.indent < column { |
1002 |
|
|
// Push the current indentation level to the stack and set the new |
1003 |
|
|
// indentation level. |
1004 |
|
|
parser.indents = append(parser.indents, parser.indent) |
1005 |
|
|
parser.indent = column |
1006 |
|
|
if len(parser.indents) > max_indents { |
1007 |
|
|
return yaml_parser_set_scanner_error(parser, |
1008 |
|
|
"while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark, |
1009 |
|
|
fmt.Sprintf("exceeded max depth of %d", max_indents)) |
1010 |
|
|
} |
1011 |
|
|
|
1012 |
|
|
// Create a token and insert it into the queue. |
1013 |
|
|
token := yaml_token_t{ |
1014 |
|
|
typ: typ, |
1015 |
|
|
start_mark: mark, |
1016 |
|
|
end_mark: mark, |
1017 |
|
|
} |
1018 |
|
|
if number > -1 { |
1019 |
|
|
number -= parser.tokens_parsed |
1020 |
|
|
} |
1021 |
|
|
yaml_insert_token(parser, number, &token) |
1022 |
|
|
} |
1023 |
|
|
return true |
1024 |
|
|
} |
1025 |
|
|
|
1026 |
|
|
// Pop indentation levels from the indents stack until the current level |
1027 |
|
|
// becomes less or equal to the column. For each indentation level, append |
1028 |
|
|
// the BLOCK-END token. |
1029 |
|
|
func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool { |
1030 |
|
|
// In the flow context, do nothing. |
1031 |
|
|
if parser.flow_level > 0 { |
1032 |
|
|
return true |
1033 |
|
|
} |
1034 |
|
|
|
1035 |
|
|
block_mark := scan_mark |
1036 |
|
|
block_mark.index-- |
1037 |
|
|
|
1038 |
|
|
// Loop through the indentation levels in the stack. |
1039 |
|
|
for parser.indent > column { |
1040 |
|
|
|
1041 |
|
|
// [Go] Reposition the end token before potential following |
1042 |
|
|
// foot comments of parent blocks. For that, search |
1043 |
|
|
// backwards for recent comments that were at the same |
1044 |
|
|
// indent as the block that is ending now. |
1045 |
|
|
stop_index := block_mark.index |
1046 |
|
|
for i := len(parser.comments) - 1; i >= 0; i-- { |
1047 |
|
|
comment := &parser.comments[i] |
1048 |
|
|
|
1049 |
|
|
if comment.end_mark.index < stop_index { |
1050 |
|
|
// Don't go back beyond the start of the comment/whitespace scan, unless column < 0. |
1051 |
|
|
// If requested indent column is < 0, then the document is over and everything else |
1052 |
|
|
// is a foot anyway. |
1053 |
|
|
break |
1054 |
|
|
} |
1055 |
|
|
if comment.start_mark.column == parser.indent+1 { |
1056 |
|
|
// This is a good match. But maybe there's a former comment |
1057 |
|
|
// at that same indent level, so keep searching. |
1058 |
|
|
block_mark = comment.start_mark |
1059 |
|
|
} |
1060 |
|
|
|
1061 |
|
|
// While the end of the former comment matches with |
1062 |
|
|
// the start of the following one, we know there's |
1063 |
|
|
// nothing in between and scanning is still safe. |
1064 |
|
|
stop_index = comment.scan_mark.index |
1065 |
|
|
} |
1066 |
|
|
|
1067 |
|
|
// Create a token and append it to the queue. |
1068 |
|
|
token := yaml_token_t{ |
1069 |
|
|
typ: yaml_BLOCK_END_TOKEN, |
1070 |
|
|
start_mark: block_mark, |
1071 |
|
|
end_mark: block_mark, |
1072 |
|
|
} |
1073 |
|
|
yaml_insert_token(parser, -1, &token) |
1074 |
|
|
|
1075 |
|
|
// Pop the indentation level. |
1076 |
|
|
parser.indent = parser.indents[len(parser.indents)-1] |
1077 |
|
|
parser.indents = parser.indents[:len(parser.indents)-1] |
1078 |
|
|
} |
1079 |
|
|
return true |
1080 |
|
|
} |
1081 |
|
|
|
1082 |
|
|
// Initialize the scanner and produce the STREAM-START token. |
1083 |
|
|
func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { |
1084 |
|
|
|
1085 |
|
|
// Set the initial indentation. |
1086 |
|
|
parser.indent = -1 |
1087 |
|
|
|
1088 |
|
|
// Initialize the simple key stack. |
1089 |
|
|
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) |
1090 |
|
|
|
1091 |
|
|
parser.simple_keys_by_tok = make(map[int]int) |
1092 |
|
|
|
1093 |
|
|
// A simple key is allowed at the beginning of the stream. |
1094 |
|
|
parser.simple_key_allowed = true |
1095 |
|
|
|
1096 |
|
|
// We have started. |
1097 |
|
|
parser.stream_start_produced = true |
1098 |
|
|
|
1099 |
|
|
// Create the STREAM-START token and append it to the queue. |
1100 |
|
|
token := yaml_token_t{ |
1101 |
|
|
typ: yaml_STREAM_START_TOKEN, |
1102 |
|
|
start_mark: parser.mark, |
1103 |
|
|
end_mark: parser.mark, |
1104 |
|
|
encoding: parser.encoding, |
1105 |
|
|
} |
1106 |
|
|
yaml_insert_token(parser, -1, &token) |
1107 |
|
|
return true |
1108 |
|
|
} |
1109 |
|
|
|
1110 |
|
|
// Produce the STREAM-END token and shut down the scanner. |
1111 |
|
|
func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { |
1112 |
|
|
|
1113 |
|
|
// Force new line. |
1114 |
|
|
if parser.mark.column != 0 { |
1115 |
|
|
parser.mark.column = 0 |
1116 |
|
|
parser.mark.line++ |
1117 |
|
|
} |
1118 |
|
|
|
1119 |
|
|
// Reset the indentation level. |
1120 |
|
|
if !yaml_parser_unroll_indent(parser, -1, parser.mark) { |
1121 |
|
|
return false |
1122 |
|
|
} |
1123 |
|
|
|
1124 |
|
|
// Reset simple keys. |
1125 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1126 |
|
|
return false |
1127 |
|
|
} |
1128 |
|
|
|
1129 |
|
|
parser.simple_key_allowed = false |
1130 |
|
|
|
1131 |
|
|
// Create the STREAM-END token and append it to the queue. |
1132 |
|
|
token := yaml_token_t{ |
1133 |
|
|
typ: yaml_STREAM_END_TOKEN, |
1134 |
|
|
start_mark: parser.mark, |
1135 |
|
|
end_mark: parser.mark, |
1136 |
|
|
} |
1137 |
|
|
yaml_insert_token(parser, -1, &token) |
1138 |
|
|
return true |
1139 |
|
|
} |
1140 |
|
|
|
1141 |
|
|
// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. |
1142 |
|
|
func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { |
1143 |
|
|
// Reset the indentation level. |
1144 |
|
|
if !yaml_parser_unroll_indent(parser, -1, parser.mark) { |
1145 |
|
|
return false |
1146 |
|
|
} |
1147 |
|
|
|
1148 |
|
|
// Reset simple keys. |
1149 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1150 |
|
|
return false |
1151 |
|
|
} |
1152 |
|
|
|
1153 |
|
|
parser.simple_key_allowed = false |
1154 |
|
|
|
1155 |
|
|
// Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. |
1156 |
|
|
token := yaml_token_t{} |
1157 |
|
|
if !yaml_parser_scan_directive(parser, &token) { |
1158 |
|
|
return false |
1159 |
|
|
} |
1160 |
|
|
// Append the token to the queue. |
1161 |
|
|
yaml_insert_token(parser, -1, &token) |
1162 |
|
|
return true |
1163 |
|
|
} |
1164 |
|
|
|
1165 |
|
|
// Produce the DOCUMENT-START or DOCUMENT-END token. |
1166 |
|
|
func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { |
1167 |
|
|
// Reset the indentation level. |
1168 |
|
|
if !yaml_parser_unroll_indent(parser, -1, parser.mark) { |
1169 |
|
|
return false |
1170 |
|
|
} |
1171 |
|
|
|
1172 |
|
|
// Reset simple keys. |
1173 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1174 |
|
|
return false |
1175 |
|
|
} |
1176 |
|
|
|
1177 |
|
|
parser.simple_key_allowed = false |
1178 |
|
|
|
1179 |
|
|
// Consume the token. |
1180 |
|
|
start_mark := parser.mark |
1181 |
|
|
|
1182 |
|
|
skip(parser) |
1183 |
|
|
skip(parser) |
1184 |
|
|
skip(parser) |
1185 |
|
|
|
1186 |
|
|
end_mark := parser.mark |
1187 |
|
|
|
1188 |
|
|
// Create the DOCUMENT-START or DOCUMENT-END token. |
1189 |
|
|
token := yaml_token_t{ |
1190 |
|
|
typ: typ, |
1191 |
|
|
start_mark: start_mark, |
1192 |
|
|
end_mark: end_mark, |
1193 |
|
|
} |
1194 |
|
|
// Append the token to the queue. |
1195 |
|
|
yaml_insert_token(parser, -1, &token) |
1196 |
|
|
return true |
1197 |
|
|
} |
1198 |
|
|
|
1199 |
|
|
// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. |
1200 |
|
|
func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { |
1201 |
|
|
|
1202 |
|
|
// The indicators '[' and '{' may start a simple key. |
1203 |
|
|
if !yaml_parser_save_simple_key(parser) { |
1204 |
|
|
return false |
1205 |
|
|
} |
1206 |
|
|
|
1207 |
|
|
// Increase the flow level. |
1208 |
|
|
if !yaml_parser_increase_flow_level(parser) { |
1209 |
|
|
return false |
1210 |
|
|
} |
1211 |
|
|
|
1212 |
|
|
// A simple key may follow the indicators '[' and '{'. |
1213 |
|
|
parser.simple_key_allowed = true |
1214 |
|
|
|
1215 |
|
|
// Consume the token. |
1216 |
|
|
start_mark := parser.mark |
1217 |
|
|
skip(parser) |
1218 |
|
|
end_mark := parser.mark |
1219 |
|
|
|
1220 |
|
|
// Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. |
1221 |
|
|
token := yaml_token_t{ |
1222 |
|
|
typ: typ, |
1223 |
|
|
start_mark: start_mark, |
1224 |
|
|
end_mark: end_mark, |
1225 |
|
|
} |
1226 |
|
|
// Append the token to the queue. |
1227 |
|
|
yaml_insert_token(parser, -1, &token) |
1228 |
|
|
return true |
1229 |
|
|
} |
1230 |
|
|
|
1231 |
|
|
// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. |
1232 |
|
|
func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { |
1233 |
|
|
// Reset any potential simple key on the current flow level. |
1234 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1235 |
|
|
return false |
1236 |
|
|
} |
1237 |
|
|
|
1238 |
|
|
// Decrease the flow level. |
1239 |
|
|
if !yaml_parser_decrease_flow_level(parser) { |
1240 |
|
|
return false |
1241 |
|
|
} |
1242 |
|
|
|
1243 |
|
|
// No simple keys after the indicators ']' and '}'. |
1244 |
|
|
parser.simple_key_allowed = false |
1245 |
|
|
|
1246 |
|
|
// Consume the token. |
1247 |
|
|
|
1248 |
|
|
start_mark := parser.mark |
1249 |
|
|
skip(parser) |
1250 |
|
|
end_mark := parser.mark |
1251 |
|
|
|
1252 |
|
|
// Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. |
1253 |
|
|
token := yaml_token_t{ |
1254 |
|
|
typ: typ, |
1255 |
|
|
start_mark: start_mark, |
1256 |
|
|
end_mark: end_mark, |
1257 |
|
|
} |
1258 |
|
|
// Append the token to the queue. |
1259 |
|
|
yaml_insert_token(parser, -1, &token) |
1260 |
|
|
return true |
1261 |
|
|
} |
1262 |
|
|
|
1263 |
|
|
// Produce the FLOW-ENTRY token. |
1264 |
|
|
func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { |
1265 |
|
|
// Reset any potential simple keys on the current flow level. |
1266 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1267 |
|
|
return false |
1268 |
|
|
} |
1269 |
|
|
|
1270 |
|
|
// Simple keys are allowed after ','. |
1271 |
|
|
parser.simple_key_allowed = true |
1272 |
|
|
|
1273 |
|
|
// Consume the token. |
1274 |
|
|
start_mark := parser.mark |
1275 |
|
|
skip(parser) |
1276 |
|
|
end_mark := parser.mark |
1277 |
|
|
|
1278 |
|
|
// Create the FLOW-ENTRY token and append it to the queue. |
1279 |
|
|
token := yaml_token_t{ |
1280 |
|
|
typ: yaml_FLOW_ENTRY_TOKEN, |
1281 |
|
|
start_mark: start_mark, |
1282 |
|
|
end_mark: end_mark, |
1283 |
|
|
} |
1284 |
|
|
yaml_insert_token(parser, -1, &token) |
1285 |
|
|
return true |
1286 |
|
|
} |
1287 |
|
|
|
1288 |
|
|
// Produce the BLOCK-ENTRY token. |
1289 |
|
|
func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { |
1290 |
|
|
// Check if the scanner is in the block context. |
1291 |
|
|
if parser.flow_level == 0 { |
1292 |
|
|
// Check if we are allowed to start a new entry. |
1293 |
|
|
if !parser.simple_key_allowed { |
1294 |
|
|
return yaml_parser_set_scanner_error(parser, "", parser.mark, |
1295 |
|
|
"block sequence entries are not allowed in this context") |
1296 |
|
|
} |
1297 |
|
|
// Add the BLOCK-SEQUENCE-START token if needed. |
1298 |
|
|
if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { |
1299 |
|
|
return false |
1300 |
|
|
} |
1301 |
|
|
} else { |
1302 |
|
|
// It is an error for the '-' indicator to occur in the flow context, |
1303 |
|
|
// but we let the Parser detect and report about it because the Parser |
1304 |
|
|
// is able to point to the context. |
1305 |
|
|
} |
1306 |
|
|
|
1307 |
|
|
// Reset any potential simple keys on the current flow level. |
1308 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1309 |
|
|
return false |
1310 |
|
|
} |
1311 |
|
|
|
1312 |
|
|
// Simple keys are allowed after '-'. |
1313 |
|
|
parser.simple_key_allowed = true |
1314 |
|
|
|
1315 |
|
|
// Consume the token. |
1316 |
|
|
start_mark := parser.mark |
1317 |
|
|
skip(parser) |
1318 |
|
|
end_mark := parser.mark |
1319 |
|
|
|
1320 |
|
|
// Create the BLOCK-ENTRY token and append it to the queue. |
1321 |
|
|
token := yaml_token_t{ |
1322 |
|
|
typ: yaml_BLOCK_ENTRY_TOKEN, |
1323 |
|
|
start_mark: start_mark, |
1324 |
|
|
end_mark: end_mark, |
1325 |
|
|
} |
1326 |
|
|
yaml_insert_token(parser, -1, &token) |
1327 |
|
|
return true |
1328 |
|
|
} |
1329 |
|
|
|
1330 |
|
|
// Produce the KEY token. |
1331 |
|
|
func yaml_parser_fetch_key(parser *yaml_parser_t) bool { |
1332 |
|
|
|
1333 |
|
|
// In the block context, additional checks are required. |
1334 |
|
|
if parser.flow_level == 0 { |
1335 |
|
|
// Check if we are allowed to start a new key (not nessesary simple). |
1336 |
|
|
if !parser.simple_key_allowed { |
1337 |
|
|
return yaml_parser_set_scanner_error(parser, "", parser.mark, |
1338 |
|
|
"mapping keys are not allowed in this context") |
1339 |
|
|
} |
1340 |
|
|
// Add the BLOCK-MAPPING-START token if needed. |
1341 |
|
|
if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { |
1342 |
|
|
return false |
1343 |
|
|
} |
1344 |
|
|
} |
1345 |
|
|
|
1346 |
|
|
// Reset any potential simple keys on the current flow level. |
1347 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1348 |
|
|
return false |
1349 |
|
|
} |
1350 |
|
|
|
1351 |
|
|
// Simple keys are allowed after '?' in the block context. |
1352 |
|
|
parser.simple_key_allowed = parser.flow_level == 0 |
1353 |
|
|
|
1354 |
|
|
// Consume the token. |
1355 |
|
|
start_mark := parser.mark |
1356 |
|
|
skip(parser) |
1357 |
|
|
end_mark := parser.mark |
1358 |
|
|
|
1359 |
|
|
// Create the KEY token and append it to the queue. |
1360 |
|
|
token := yaml_token_t{ |
1361 |
|
|
typ: yaml_KEY_TOKEN, |
1362 |
|
|
start_mark: start_mark, |
1363 |
|
|
end_mark: end_mark, |
1364 |
|
|
} |
1365 |
|
|
yaml_insert_token(parser, -1, &token) |
1366 |
|
|
return true |
1367 |
|
|
} |
1368 |
|
|
|
1369 |
|
|
// Produce the VALUE token. |
1370 |
|
|
func yaml_parser_fetch_value(parser *yaml_parser_t) bool { |
1371 |
|
|
|
1372 |
|
|
simple_key := &parser.simple_keys[len(parser.simple_keys)-1] |
1373 |
|
|
|
1374 |
|
|
// Have we found a simple key? |
1375 |
|
|
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { |
1376 |
|
|
return false |
1377 |
|
|
|
1378 |
|
|
} else if valid { |
1379 |
|
|
|
1380 |
|
|
// Create the KEY token and insert it into the queue. |
1381 |
|
|
token := yaml_token_t{ |
1382 |
|
|
typ: yaml_KEY_TOKEN, |
1383 |
|
|
start_mark: simple_key.mark, |
1384 |
|
|
end_mark: simple_key.mark, |
1385 |
|
|
} |
1386 |
|
|
yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) |
1387 |
|
|
|
1388 |
|
|
// In the block context, we may need to add the BLOCK-MAPPING-START token. |
1389 |
|
|
if !yaml_parser_roll_indent(parser, simple_key.mark.column, |
1390 |
|
|
simple_key.token_number, |
1391 |
|
|
yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { |
1392 |
|
|
return false |
1393 |
|
|
} |
1394 |
|
|
|
1395 |
|
|
// Remove the simple key. |
1396 |
|
|
simple_key.possible = false |
1397 |
|
|
delete(parser.simple_keys_by_tok, simple_key.token_number) |
1398 |
|
|
|
1399 |
|
|
// A simple key cannot follow another simple key. |
1400 |
|
|
parser.simple_key_allowed = false |
1401 |
|
|
|
1402 |
|
|
} else { |
1403 |
|
|
// The ':' indicator follows a complex key. |
1404 |
|
|
|
1405 |
|
|
// In the block context, extra checks are required. |
1406 |
|
|
if parser.flow_level == 0 { |
1407 |
|
|
|
1408 |
|
|
// Check if we are allowed to start a complex value. |
1409 |
|
|
if !parser.simple_key_allowed { |
1410 |
|
|
return yaml_parser_set_scanner_error(parser, "", parser.mark, |
1411 |
|
|
"mapping values are not allowed in this context") |
1412 |
|
|
} |
1413 |
|
|
|
1414 |
|
|
// Add the BLOCK-MAPPING-START token if needed. |
1415 |
|
|
if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { |
1416 |
|
|
return false |
1417 |
|
|
} |
1418 |
|
|
} |
1419 |
|
|
|
1420 |
|
|
// Simple keys after ':' are allowed in the block context. |
1421 |
|
|
parser.simple_key_allowed = parser.flow_level == 0 |
1422 |
|
|
} |
1423 |
|
|
|
1424 |
|
|
// Consume the token. |
1425 |
|
|
start_mark := parser.mark |
1426 |
|
|
skip(parser) |
1427 |
|
|
end_mark := parser.mark |
1428 |
|
|
|
1429 |
|
|
// Create the VALUE token and append it to the queue. |
1430 |
|
|
token := yaml_token_t{ |
1431 |
|
|
typ: yaml_VALUE_TOKEN, |
1432 |
|
|
start_mark: start_mark, |
1433 |
|
|
end_mark: end_mark, |
1434 |
|
|
} |
1435 |
|
|
yaml_insert_token(parser, -1, &token) |
1436 |
|
|
return true |
1437 |
|
|
} |
1438 |
|
|
|
1439 |
|
|
// Produce the ALIAS or ANCHOR token. |
1440 |
|
|
func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { |
1441 |
|
|
// An anchor or an alias could be a simple key. |
1442 |
|
|
if !yaml_parser_save_simple_key(parser) { |
1443 |
|
|
return false |
1444 |
|
|
} |
1445 |
|
|
|
1446 |
|
|
// A simple key cannot follow an anchor or an alias. |
1447 |
|
|
parser.simple_key_allowed = false |
1448 |
|
|
|
1449 |
|
|
// Create the ALIAS or ANCHOR token and append it to the queue. |
1450 |
|
|
var token yaml_token_t |
1451 |
|
|
if !yaml_parser_scan_anchor(parser, &token, typ) { |
1452 |
|
|
return false |
1453 |
|
|
} |
1454 |
|
|
yaml_insert_token(parser, -1, &token) |
1455 |
|
|
return true |
1456 |
|
|
} |
1457 |
|
|
|
1458 |
|
|
// Produce the TAG token. |
1459 |
|
|
func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { |
1460 |
|
|
// A tag could be a simple key. |
1461 |
|
|
if !yaml_parser_save_simple_key(parser) { |
1462 |
|
|
return false |
1463 |
|
|
} |
1464 |
|
|
|
1465 |
|
|
// A simple key cannot follow a tag. |
1466 |
|
|
parser.simple_key_allowed = false |
1467 |
|
|
|
1468 |
|
|
// Create the TAG token and append it to the queue. |
1469 |
|
|
var token yaml_token_t |
1470 |
|
|
if !yaml_parser_scan_tag(parser, &token) { |
1471 |
|
|
return false |
1472 |
|
|
} |
1473 |
|
|
yaml_insert_token(parser, -1, &token) |
1474 |
|
|
return true |
1475 |
|
|
} |
1476 |
|
|
|
1477 |
|
|
// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. |
1478 |
|
|
func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { |
1479 |
|
|
// Remove any potential simple keys. |
1480 |
|
|
if !yaml_parser_remove_simple_key(parser) { |
1481 |
|
|
return false |
1482 |
|
|
} |
1483 |
|
|
|
1484 |
|
|
// A simple key may follow a block scalar. |
1485 |
|
|
parser.simple_key_allowed = true |
1486 |
|
|
|
1487 |
|
|
// Create the SCALAR token and append it to the queue. |
1488 |
|
|
var token yaml_token_t |
1489 |
|
|
if !yaml_parser_scan_block_scalar(parser, &token, literal) { |
1490 |
|
|
return false |
1491 |
|
|
} |
1492 |
|
|
yaml_insert_token(parser, -1, &token) |
1493 |
|
|
return true |
1494 |
|
|
} |
1495 |
|
|
|
1496 |
|
|
// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. |
1497 |
|
|
func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { |
1498 |
|
|
// A plain scalar could be a simple key. |
1499 |
|
|
if !yaml_parser_save_simple_key(parser) { |
1500 |
|
|
return false |
1501 |
|
|
} |
1502 |
|
|
|
1503 |
|
|
// A simple key cannot follow a flow scalar. |
1504 |
|
|
parser.simple_key_allowed = false |
1505 |
|
|
|
1506 |
|
|
// Create the SCALAR token and append it to the queue. |
1507 |
|
|
var token yaml_token_t |
1508 |
|
|
if !yaml_parser_scan_flow_scalar(parser, &token, single) { |
1509 |
|
|
return false |
1510 |
|
|
} |
1511 |
|
|
yaml_insert_token(parser, -1, &token) |
1512 |
|
|
return true |
1513 |
|
|
} |
1514 |
|
|
|
1515 |
|
|
// Produce the SCALAR(...,plain) token. |
1516 |
|
|
func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { |
1517 |
|
|
// A plain scalar could be a simple key. |
1518 |
|
|
if !yaml_parser_save_simple_key(parser) { |
1519 |
|
|
return false |
1520 |
|
|
} |
1521 |
|
|
|
1522 |
|
|
// A simple key cannot follow a flow scalar. |
1523 |
|
|
parser.simple_key_allowed = false |
1524 |
|
|
|
1525 |
|
|
// Create the SCALAR token and append it to the queue. |
1526 |
|
|
var token yaml_token_t |
1527 |
|
|
if !yaml_parser_scan_plain_scalar(parser, &token) { |
1528 |
|
|
return false |
1529 |
|
|
} |
1530 |
|
|
yaml_insert_token(parser, -1, &token) |
1531 |
|
|
return true |
1532 |
|
|
} |
1533 |
|
|
|
1534 |
|
|
// Eat whitespaces and comments until the next token is found. |
1535 |
|
|
func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { |
1536 |
|
|
|
1537 |
|
|
scan_mark := parser.mark |
1538 |
|
|
|
1539 |
|
|
// Until the next token is not found. |
1540 |
|
|
for { |
1541 |
|
|
// Allow the BOM mark to start a line. |
1542 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1543 |
|
|
return false |
1544 |
|
|
} |
1545 |
|
|
if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { |
1546 |
|
|
skip(parser) |
1547 |
|
|
} |
1548 |
|
|
|
1549 |
|
|
// Eat whitespaces. |
1550 |
|
|
// Tabs are allowed: |
1551 |
|
|
// - in the flow context |
1552 |
|
|
// - in the block context, but not at the beginning of the line or |
1553 |
|
|
// after '-', '?', or ':' (complex value). |
1554 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1555 |
|
|
return false |
1556 |
|
|
} |
1557 |
|
|
|
1558 |
|
|
for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { |
1559 |
|
|
skip(parser) |
1560 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1561 |
|
|
return false |
1562 |
|
|
} |
1563 |
|
|
} |
1564 |
|
|
|
1565 |
|
|
// Check if we just had a line comment under a sequence entry that |
1566 |
|
|
// looks more like a header to the following content. Similar to this: |
1567 |
|
|
// |
1568 |
|
|
// - # The comment |
1569 |
|
|
// - Some data |
1570 |
|
|
// |
1571 |
|
|
// If so, transform the line comment to a head comment and reposition. |
1572 |
|
|
if len(parser.comments) > 0 && len(parser.tokens) > 1 { |
1573 |
|
|
tokenA := parser.tokens[len(parser.tokens)-2] |
1574 |
|
|
tokenB := parser.tokens[len(parser.tokens)-1] |
1575 |
|
|
comment := &parser.comments[len(parser.comments)-1] |
1576 |
|
|
if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) { |
1577 |
|
|
// If it was in the prior line, reposition so it becomes a |
1578 |
|
|
// header of the follow up token. Otherwise, keep it in place |
1579 |
|
|
// so it becomes a header of the former. |
1580 |
|
|
comment.head = comment.line |
1581 |
|
|
comment.line = nil |
1582 |
|
|
if comment.start_mark.line == parser.mark.line-1 { |
1583 |
|
|
comment.token_mark = parser.mark |
1584 |
|
|
} |
1585 |
|
|
} |
1586 |
|
|
} |
1587 |
|
|
|
1588 |
|
|
// Eat a comment until a line break. |
1589 |
|
|
if parser.buffer[parser.buffer_pos] == '#' { |
1590 |
|
|
if !yaml_parser_scan_comments(parser, scan_mark) { |
1591 |
|
|
return false |
1592 |
|
|
} |
1593 |
|
|
} |
1594 |
|
|
|
1595 |
|
|
// If it is a line break, eat it. |
1596 |
|
|
if is_break(parser.buffer, parser.buffer_pos) { |
1597 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
1598 |
|
|
return false |
1599 |
|
|
} |
1600 |
|
|
skip_line(parser) |
1601 |
|
|
|
1602 |
|
|
// In the block context, a new line may start a simple key. |
1603 |
|
|
if parser.flow_level == 0 { |
1604 |
|
|
parser.simple_key_allowed = true |
1605 |
|
|
} |
1606 |
|
|
} else { |
1607 |
|
|
break // We have found a token. |
1608 |
|
|
} |
1609 |
|
|
} |
1610 |
|
|
|
1611 |
|
|
return true |
1612 |
|
|
} |
1613 |
|
|
|
1614 |
|
|
// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. |
1615 |
|
|
// |
1616 |
|
|
// Scope: |
1617 |
|
|
// %YAML 1.1 # a comment \n |
1618 |
|
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1619 |
|
|
// %TAG !yaml! tag:yaml.org,2002: \n |
1620 |
|
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1621 |
|
|
// |
1622 |
|
|
func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { |
1623 |
|
|
// Eat '%'. |
1624 |
|
|
start_mark := parser.mark |
1625 |
|
|
skip(parser) |
1626 |
|
|
|
1627 |
|
|
// Scan the directive name. |
1628 |
|
|
var name []byte |
1629 |
|
|
if !yaml_parser_scan_directive_name(parser, start_mark, &name) { |
1630 |
|
|
return false |
1631 |
|
|
} |
1632 |
|
|
|
1633 |
|
|
// Is it a YAML directive? |
1634 |
|
|
if bytes.Equal(name, []byte("YAML")) { |
1635 |
|
|
// Scan the VERSION directive value. |
1636 |
|
|
var major, minor int8 |
1637 |
|
|
if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { |
1638 |
|
|
return false |
1639 |
|
|
} |
1640 |
|
|
end_mark := parser.mark |
1641 |
|
|
|
1642 |
|
|
// Create a VERSION-DIRECTIVE token. |
1643 |
|
|
*token = yaml_token_t{ |
1644 |
|
|
typ: yaml_VERSION_DIRECTIVE_TOKEN, |
1645 |
|
|
start_mark: start_mark, |
1646 |
|
|
end_mark: end_mark, |
1647 |
|
|
major: major, |
1648 |
|
|
minor: minor, |
1649 |
|
|
} |
1650 |
|
|
|
1651 |
|
|
// Is it a TAG directive? |
1652 |
|
|
} else if bytes.Equal(name, []byte("TAG")) { |
1653 |
|
|
// Scan the TAG directive value. |
1654 |
|
|
var handle, prefix []byte |
1655 |
|
|
if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { |
1656 |
|
|
return false |
1657 |
|
|
} |
1658 |
|
|
end_mark := parser.mark |
1659 |
|
|
|
1660 |
|
|
// Create a TAG-DIRECTIVE token. |
1661 |
|
|
*token = yaml_token_t{ |
1662 |
|
|
typ: yaml_TAG_DIRECTIVE_TOKEN, |
1663 |
|
|
start_mark: start_mark, |
1664 |
|
|
end_mark: end_mark, |
1665 |
|
|
value: handle, |
1666 |
|
|
prefix: prefix, |
1667 |
|
|
} |
1668 |
|
|
|
1669 |
|
|
// Unknown directive. |
1670 |
|
|
} else { |
1671 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a directive", |
1672 |
|
|
start_mark, "found unknown directive name") |
1673 |
|
|
return false |
1674 |
|
|
} |
1675 |
|
|
|
1676 |
|
|
// Eat the rest of the line including any comments. |
1677 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1678 |
|
|
return false |
1679 |
|
|
} |
1680 |
|
|
|
1681 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) { |
1682 |
|
|
skip(parser) |
1683 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1684 |
|
|
return false |
1685 |
|
|
} |
1686 |
|
|
} |
1687 |
|
|
|
1688 |
|
|
if parser.buffer[parser.buffer_pos] == '#' { |
1689 |
|
|
// [Go] Discard this inline comment for the time being. |
1690 |
|
|
//if !yaml_parser_scan_line_comment(parser, start_mark) { |
1691 |
|
|
// return false |
1692 |
|
|
//} |
1693 |
|
|
for !is_breakz(parser.buffer, parser.buffer_pos) { |
1694 |
|
|
skip(parser) |
1695 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1696 |
|
|
return false |
1697 |
|
|
} |
1698 |
|
|
} |
1699 |
|
|
} |
1700 |
|
|
|
1701 |
|
|
// Check if we are at the end of the line. |
1702 |
|
|
if !is_breakz(parser.buffer, parser.buffer_pos) { |
1703 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a directive", |
1704 |
|
|
start_mark, "did not find expected comment or line break") |
1705 |
|
|
return false |
1706 |
|
|
} |
1707 |
|
|
|
1708 |
|
|
// Eat a line break. |
1709 |
|
|
if is_break(parser.buffer, parser.buffer_pos) { |
1710 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
1711 |
|
|
return false |
1712 |
|
|
} |
1713 |
|
|
skip_line(parser) |
1714 |
|
|
} |
1715 |
|
|
|
1716 |
|
|
return true |
1717 |
|
|
} |
1718 |
|
|
|
1719 |
|
|
// Scan the directive name. |
1720 |
|
|
// |
1721 |
|
|
// Scope: |
1722 |
|
|
// %YAML 1.1 # a comment \n |
1723 |
|
|
// ^^^^ |
1724 |
|
|
// %TAG !yaml! tag:yaml.org,2002: \n |
1725 |
|
|
// ^^^ |
1726 |
|
|
// |
1727 |
|
|
func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { |
1728 |
|
|
// Consume the directive name. |
1729 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1730 |
|
|
return false |
1731 |
|
|
} |
1732 |
|
|
|
1733 |
|
|
var s []byte |
1734 |
|
|
for is_alpha(parser.buffer, parser.buffer_pos) { |
1735 |
|
|
s = read(parser, s) |
1736 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1737 |
|
|
return false |
1738 |
|
|
} |
1739 |
|
|
} |
1740 |
|
|
|
1741 |
|
|
// Check if the name is empty. |
1742 |
|
|
if len(s) == 0 { |
1743 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a directive", |
1744 |
|
|
start_mark, "could not find expected directive name") |
1745 |
|
|
return false |
1746 |
|
|
} |
1747 |
|
|
|
1748 |
|
|
// Check for an blank character after the name. |
1749 |
|
|
if !is_blankz(parser.buffer, parser.buffer_pos) { |
1750 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a directive", |
1751 |
|
|
start_mark, "found unexpected non-alphabetical character") |
1752 |
|
|
return false |
1753 |
|
|
} |
1754 |
|
|
*name = s |
1755 |
|
|
return true |
1756 |
|
|
} |
1757 |
|
|
|
1758 |
|
|
// Scan the value of VERSION-DIRECTIVE. |
1759 |
|
|
// |
1760 |
|
|
// Scope: |
1761 |
|
|
// %YAML 1.1 # a comment \n |
1762 |
|
|
// ^^^^^^ |
1763 |
|
|
func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { |
1764 |
|
|
// Eat whitespaces. |
1765 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1766 |
|
|
return false |
1767 |
|
|
} |
1768 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) { |
1769 |
|
|
skip(parser) |
1770 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1771 |
|
|
return false |
1772 |
|
|
} |
1773 |
|
|
} |
1774 |
|
|
|
1775 |
|
|
// Consume the major version number. |
1776 |
|
|
if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { |
1777 |
|
|
return false |
1778 |
|
|
} |
1779 |
|
|
|
1780 |
|
|
// Eat '.'. |
1781 |
|
|
if parser.buffer[parser.buffer_pos] != '.' { |
1782 |
|
|
return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
1783 |
|
|
start_mark, "did not find expected digit or '.' character") |
1784 |
|
|
} |
1785 |
|
|
|
1786 |
|
|
skip(parser) |
1787 |
|
|
|
1788 |
|
|
// Consume the minor version number. |
1789 |
|
|
if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { |
1790 |
|
|
return false |
1791 |
|
|
} |
1792 |
|
|
return true |
1793 |
|
|
} |
1794 |
|
|
|
1795 |
|
|
const max_number_length = 2 |
1796 |
|
|
|
1797 |
|
|
// Scan the version number of VERSION-DIRECTIVE. |
1798 |
|
|
// |
1799 |
|
|
// Scope: |
1800 |
|
|
// %YAML 1.1 # a comment \n |
1801 |
|
|
// ^ |
1802 |
|
|
// %YAML 1.1 # a comment \n |
1803 |
|
|
// ^ |
1804 |
|
|
func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { |
1805 |
|
|
|
1806 |
|
|
// Repeat while the next character is digit. |
1807 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1808 |
|
|
return false |
1809 |
|
|
} |
1810 |
|
|
var value, length int8 |
1811 |
|
|
for is_digit(parser.buffer, parser.buffer_pos) { |
1812 |
|
|
// Check if the number is too long. |
1813 |
|
|
length++ |
1814 |
|
|
if length > max_number_length { |
1815 |
|
|
return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
1816 |
|
|
start_mark, "found extremely long version number") |
1817 |
|
|
} |
1818 |
|
|
value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) |
1819 |
|
|
skip(parser) |
1820 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1821 |
|
|
return false |
1822 |
|
|
} |
1823 |
|
|
} |
1824 |
|
|
|
1825 |
|
|
// Check if the number was present. |
1826 |
|
|
if length == 0 { |
1827 |
|
|
return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", |
1828 |
|
|
start_mark, "did not find expected version number") |
1829 |
|
|
} |
1830 |
|
|
*number = value |
1831 |
|
|
return true |
1832 |
|
|
} |
1833 |
|
|
|
1834 |
|
|
// Scan the value of a TAG-DIRECTIVE token. |
1835 |
|
|
// |
1836 |
|
|
// Scope: |
1837 |
|
|
// %TAG !yaml! tag:yaml.org,2002: \n |
1838 |
|
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1839 |
|
|
// |
1840 |
|
|
func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { |
1841 |
|
|
var handle_value, prefix_value []byte |
1842 |
|
|
|
1843 |
|
|
// Eat whitespaces. |
1844 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1845 |
|
|
return false |
1846 |
|
|
} |
1847 |
|
|
|
1848 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) { |
1849 |
|
|
skip(parser) |
1850 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1851 |
|
|
return false |
1852 |
|
|
} |
1853 |
|
|
} |
1854 |
|
|
|
1855 |
|
|
// Scan a handle. |
1856 |
|
|
if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { |
1857 |
|
|
return false |
1858 |
|
|
} |
1859 |
|
|
|
1860 |
|
|
// Expect a whitespace. |
1861 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1862 |
|
|
return false |
1863 |
|
|
} |
1864 |
|
|
if !is_blank(parser.buffer, parser.buffer_pos) { |
1865 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", |
1866 |
|
|
start_mark, "did not find expected whitespace") |
1867 |
|
|
return false |
1868 |
|
|
} |
1869 |
|
|
|
1870 |
|
|
// Eat whitespaces. |
1871 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) { |
1872 |
|
|
skip(parser) |
1873 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1874 |
|
|
return false |
1875 |
|
|
} |
1876 |
|
|
} |
1877 |
|
|
|
1878 |
|
|
// Scan a prefix. |
1879 |
|
|
if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { |
1880 |
|
|
return false |
1881 |
|
|
} |
1882 |
|
|
|
1883 |
|
|
// Expect a whitespace or line break. |
1884 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1885 |
|
|
return false |
1886 |
|
|
} |
1887 |
|
|
if !is_blankz(parser.buffer, parser.buffer_pos) { |
1888 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", |
1889 |
|
|
start_mark, "did not find expected whitespace or line break") |
1890 |
|
|
return false |
1891 |
|
|
} |
1892 |
|
|
|
1893 |
|
|
*handle = handle_value |
1894 |
|
|
*prefix = prefix_value |
1895 |
|
|
return true |
1896 |
|
|
} |
1897 |
|
|
|
1898 |
|
|
func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { |
1899 |
|
|
var s []byte |
1900 |
|
|
|
1901 |
|
|
// Eat the indicator character. |
1902 |
|
|
start_mark := parser.mark |
1903 |
|
|
skip(parser) |
1904 |
|
|
|
1905 |
|
|
// Consume the value. |
1906 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1907 |
|
|
return false |
1908 |
|
|
} |
1909 |
|
|
|
1910 |
|
|
for is_alpha(parser.buffer, parser.buffer_pos) { |
1911 |
|
|
s = read(parser, s) |
1912 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
1913 |
|
|
return false |
1914 |
|
|
} |
1915 |
|
|
} |
1916 |
|
|
|
1917 |
|
|
end_mark := parser.mark |
1918 |
|
|
|
1919 |
|
|
/* |
1920 |
|
|
* Check if length of the anchor is greater than 0 and it is followed by |
1921 |
|
|
* a whitespace character or one of the indicators: |
1922 |
|
|
* |
1923 |
|
|
* '?', ':', ',', ']', '}', '%', '@', '`'. |
1924 |
|
|
*/ |
1925 |
|
|
|
1926 |
|
|
if len(s) == 0 || |
1927 |
|
|
!(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || |
1928 |
|
|
parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || |
1929 |
|
|
parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || |
1930 |
|
|
parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || |
1931 |
|
|
parser.buffer[parser.buffer_pos] == '`') { |
1932 |
|
|
context := "while scanning an alias" |
1933 |
|
|
if typ == yaml_ANCHOR_TOKEN { |
1934 |
|
|
context = "while scanning an anchor" |
1935 |
|
|
} |
1936 |
|
|
yaml_parser_set_scanner_error(parser, context, start_mark, |
1937 |
|
|
"did not find expected alphabetic or numeric character") |
1938 |
|
|
return false |
1939 |
|
|
} |
1940 |
|
|
|
1941 |
|
|
// Create a token. |
1942 |
|
|
*token = yaml_token_t{ |
1943 |
|
|
typ: typ, |
1944 |
|
|
start_mark: start_mark, |
1945 |
|
|
end_mark: end_mark, |
1946 |
|
|
value: s, |
1947 |
|
|
} |
1948 |
|
|
|
1949 |
|
|
return true |
1950 |
|
|
} |
1951 |
|
|
|
1952 |
|
|
/* |
1953 |
|
|
* Scan a TAG token. |
1954 |
|
|
*/ |
1955 |
|
|
|
1956 |
|
|
func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { |
1957 |
|
|
var handle, suffix []byte |
1958 |
|
|
|
1959 |
|
|
start_mark := parser.mark |
1960 |
|
|
|
1961 |
|
|
// Check if the tag is in the canonical form. |
1962 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
1963 |
|
|
return false |
1964 |
|
|
} |
1965 |
|
|
|
1966 |
|
|
if parser.buffer[parser.buffer_pos+1] == '<' { |
1967 |
|
|
// Keep the handle as '' |
1968 |
|
|
|
1969 |
|
|
// Eat '!<' |
1970 |
|
|
skip(parser) |
1971 |
|
|
skip(parser) |
1972 |
|
|
|
1973 |
|
|
// Consume the tag value. |
1974 |
|
|
if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { |
1975 |
|
|
return false |
1976 |
|
|
} |
1977 |
|
|
|
1978 |
|
|
// Check for '>' and eat it. |
1979 |
|
|
if parser.buffer[parser.buffer_pos] != '>' { |
1980 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a tag", |
1981 |
|
|
start_mark, "did not find the expected '>'") |
1982 |
|
|
return false |
1983 |
|
|
} |
1984 |
|
|
|
1985 |
|
|
skip(parser) |
1986 |
|
|
} else { |
1987 |
|
|
// The tag has either the '!suffix' or the '!handle!suffix' form. |
1988 |
|
|
|
1989 |
|
|
// First, try to scan a handle. |
1990 |
|
|
if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { |
1991 |
|
|
return false |
1992 |
|
|
} |
1993 |
|
|
|
1994 |
|
|
// Check if it is, indeed, handle. |
1995 |
|
|
if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { |
1996 |
|
|
// Scan the suffix now. |
1997 |
|
|
if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { |
1998 |
|
|
return false |
1999 |
|
|
} |
2000 |
|
|
} else { |
2001 |
|
|
// It wasn't a handle after all. Scan the rest of the tag. |
2002 |
|
|
if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { |
2003 |
|
|
return false |
2004 |
|
|
} |
2005 |
|
|
|
2006 |
|
|
// Set the handle to '!'. |
2007 |
|
|
handle = []byte{'!'} |
2008 |
|
|
|
2009 |
|
|
// A special case: the '!' tag. Set the handle to '' and the |
2010 |
|
|
// suffix to '!'. |
2011 |
|
|
if len(suffix) == 0 { |
2012 |
|
|
handle, suffix = suffix, handle |
2013 |
|
|
} |
2014 |
|
|
} |
2015 |
|
|
} |
2016 |
|
|
|
2017 |
|
|
// Check the character which ends the tag. |
2018 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2019 |
|
|
return false |
2020 |
|
|
} |
2021 |
|
|
if !is_blankz(parser.buffer, parser.buffer_pos) { |
2022 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a tag", |
2023 |
|
|
start_mark, "did not find expected whitespace or line break") |
2024 |
|
|
return false |
2025 |
|
|
} |
2026 |
|
|
|
2027 |
|
|
end_mark := parser.mark |
2028 |
|
|
|
2029 |
|
|
// Create a token. |
2030 |
|
|
*token = yaml_token_t{ |
2031 |
|
|
typ: yaml_TAG_TOKEN, |
2032 |
|
|
start_mark: start_mark, |
2033 |
|
|
end_mark: end_mark, |
2034 |
|
|
value: handle, |
2035 |
|
|
suffix: suffix, |
2036 |
|
|
} |
2037 |
|
|
return true |
2038 |
|
|
} |
2039 |
|
|
|
2040 |
|
|
// Scan a tag handle. |
2041 |
|
|
func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { |
2042 |
|
|
// Check the initial '!' character. |
2043 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2044 |
|
|
return false |
2045 |
|
|
} |
2046 |
|
|
if parser.buffer[parser.buffer_pos] != '!' { |
2047 |
|
|
yaml_parser_set_scanner_tag_error(parser, directive, |
2048 |
|
|
start_mark, "did not find expected '!'") |
2049 |
|
|
return false |
2050 |
|
|
} |
2051 |
|
|
|
2052 |
|
|
var s []byte |
2053 |
|
|
|
2054 |
|
|
// Copy the '!' character. |
2055 |
|
|
s = read(parser, s) |
2056 |
|
|
|
2057 |
|
|
// Copy all subsequent alphabetical and numerical characters. |
2058 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2059 |
|
|
return false |
2060 |
|
|
} |
2061 |
|
|
for is_alpha(parser.buffer, parser.buffer_pos) { |
2062 |
|
|
s = read(parser, s) |
2063 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2064 |
|
|
return false |
2065 |
|
|
} |
2066 |
|
|
} |
2067 |
|
|
|
2068 |
|
|
// Check if the trailing character is '!' and copy it. |
2069 |
|
|
if parser.buffer[parser.buffer_pos] == '!' { |
2070 |
|
|
s = read(parser, s) |
2071 |
|
|
} else { |
2072 |
|
|
// It's either the '!' tag or not really a tag handle. If it's a %TAG |
2073 |
|
|
// directive, it's an error. If it's a tag token, it must be a part of URI. |
2074 |
|
|
if directive && string(s) != "!" { |
2075 |
|
|
yaml_parser_set_scanner_tag_error(parser, directive, |
2076 |
|
|
start_mark, "did not find expected '!'") |
2077 |
|
|
return false |
2078 |
|
|
} |
2079 |
|
|
} |
2080 |
|
|
|
2081 |
|
|
*handle = s |
2082 |
|
|
return true |
2083 |
|
|
} |
2084 |
|
|
|
2085 |
|
|
// Scan a tag. |
2086 |
|
|
func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { |
2087 |
|
|
//size_t length = head ? strlen((char *)head) : 0 |
2088 |
|
|
var s []byte |
2089 |
|
|
hasTag := len(head) > 0 |
2090 |
|
|
|
2091 |
|
|
// Copy the head if needed. |
2092 |
|
|
// |
2093 |
|
|
// Note that we don't copy the leading '!' character. |
2094 |
|
|
if len(head) > 1 { |
2095 |
|
|
s = append(s, head[1:]...) |
2096 |
|
|
} |
2097 |
|
|
|
2098 |
|
|
// Scan the tag. |
2099 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2100 |
|
|
return false |
2101 |
|
|
} |
2102 |
|
|
|
2103 |
|
|
// The set of characters that may appear in URI is as follows: |
2104 |
|
|
// |
2105 |
|
|
// '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', |
2106 |
|
|
// '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', |
2107 |
|
|
// '%'. |
2108 |
|
|
// [Go] TODO Convert this into more reasonable logic. |
2109 |
|
|
for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || |
2110 |
|
|
parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || |
2111 |
|
|
parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || |
2112 |
|
|
parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || |
2113 |
|
|
parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || |
2114 |
|
|
parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || |
2115 |
|
|
parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || |
2116 |
|
|
parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || |
2117 |
|
|
parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || |
2118 |
|
|
parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || |
2119 |
|
|
parser.buffer[parser.buffer_pos] == '%' { |
2120 |
|
|
// Check if it is a URI-escape sequence. |
2121 |
|
|
if parser.buffer[parser.buffer_pos] == '%' { |
2122 |
|
|
if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { |
2123 |
|
|
return false |
2124 |
|
|
} |
2125 |
|
|
} else { |
2126 |
|
|
s = read(parser, s) |
2127 |
|
|
} |
2128 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2129 |
|
|
return false |
2130 |
|
|
} |
2131 |
|
|
hasTag = true |
2132 |
|
|
} |
2133 |
|
|
|
2134 |
|
|
if !hasTag { |
2135 |
|
|
yaml_parser_set_scanner_tag_error(parser, directive, |
2136 |
|
|
start_mark, "did not find expected tag URI") |
2137 |
|
|
return false |
2138 |
|
|
} |
2139 |
|
|
*uri = s |
2140 |
|
|
return true |
2141 |
|
|
} |
2142 |
|
|
|
2143 |
|
|
// Decode an URI-escape sequence corresponding to a single UTF-8 character. |
2144 |
|
|
func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { |
2145 |
|
|
|
2146 |
|
|
// Decode the required number of characters. |
2147 |
|
|
w := 1024 |
2148 |
|
|
for w > 0 { |
2149 |
|
|
// Check for a URI-escaped octet. |
2150 |
|
|
if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { |
2151 |
|
|
return false |
2152 |
|
|
} |
2153 |
|
|
|
2154 |
|
|
if !(parser.buffer[parser.buffer_pos] == '%' && |
2155 |
|
|
is_hex(parser.buffer, parser.buffer_pos+1) && |
2156 |
|
|
is_hex(parser.buffer, parser.buffer_pos+2)) { |
2157 |
|
|
return yaml_parser_set_scanner_tag_error(parser, directive, |
2158 |
|
|
start_mark, "did not find URI escaped octet") |
2159 |
|
|
} |
2160 |
|
|
|
2161 |
|
|
// Get the octet. |
2162 |
|
|
octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) |
2163 |
|
|
|
2164 |
|
|
// If it is the leading octet, determine the length of the UTF-8 sequence. |
2165 |
|
|
if w == 1024 { |
2166 |
|
|
w = width(octet) |
2167 |
|
|
if w == 0 { |
2168 |
|
|
return yaml_parser_set_scanner_tag_error(parser, directive, |
2169 |
|
|
start_mark, "found an incorrect leading UTF-8 octet") |
2170 |
|
|
} |
2171 |
|
|
} else { |
2172 |
|
|
// Check if the trailing octet is correct. |
2173 |
|
|
if octet&0xC0 != 0x80 { |
2174 |
|
|
return yaml_parser_set_scanner_tag_error(parser, directive, |
2175 |
|
|
start_mark, "found an incorrect trailing UTF-8 octet") |
2176 |
|
|
} |
2177 |
|
|
} |
2178 |
|
|
|
2179 |
|
|
// Copy the octet and move the pointers. |
2180 |
|
|
*s = append(*s, octet) |
2181 |
|
|
skip(parser) |
2182 |
|
|
skip(parser) |
2183 |
|
|
skip(parser) |
2184 |
|
|
w-- |
2185 |
|
|
} |
2186 |
|
|
return true |
2187 |
|
|
} |
2188 |
|
|
|
2189 |
|
|
// Scan a block scalar. |
2190 |
|
|
func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { |
2191 |
|
|
// Eat the indicator '|' or '>'. |
2192 |
|
|
start_mark := parser.mark |
2193 |
|
|
skip(parser) |
2194 |
|
|
|
2195 |
|
|
// Scan the additional block scalar indicators. |
2196 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2197 |
|
|
return false |
2198 |
|
|
} |
2199 |
|
|
|
2200 |
|
|
// Check for a chomping indicator. |
2201 |
|
|
var chomping, increment int |
2202 |
|
|
if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { |
2203 |
|
|
// Set the chomping method and eat the indicator. |
2204 |
|
|
if parser.buffer[parser.buffer_pos] == '+' { |
2205 |
|
|
chomping = +1 |
2206 |
|
|
} else { |
2207 |
|
|
chomping = -1 |
2208 |
|
|
} |
2209 |
|
|
skip(parser) |
2210 |
|
|
|
2211 |
|
|
// Check for an indentation indicator. |
2212 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2213 |
|
|
return false |
2214 |
|
|
} |
2215 |
|
|
if is_digit(parser.buffer, parser.buffer_pos) { |
2216 |
|
|
// Check that the indentation is greater than 0. |
2217 |
|
|
if parser.buffer[parser.buffer_pos] == '0' { |
2218 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a block scalar", |
2219 |
|
|
start_mark, "found an indentation indicator equal to 0") |
2220 |
|
|
return false |
2221 |
|
|
} |
2222 |
|
|
|
2223 |
|
|
// Get the indentation level and eat the indicator. |
2224 |
|
|
increment = as_digit(parser.buffer, parser.buffer_pos) |
2225 |
|
|
skip(parser) |
2226 |
|
|
} |
2227 |
|
|
|
2228 |
|
|
} else if is_digit(parser.buffer, parser.buffer_pos) { |
2229 |
|
|
// Do the same as above, but in the opposite order. |
2230 |
|
|
|
2231 |
|
|
if parser.buffer[parser.buffer_pos] == '0' { |
2232 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a block scalar", |
2233 |
|
|
start_mark, "found an indentation indicator equal to 0") |
2234 |
|
|
return false |
2235 |
|
|
} |
2236 |
|
|
increment = as_digit(parser.buffer, parser.buffer_pos) |
2237 |
|
|
skip(parser) |
2238 |
|
|
|
2239 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2240 |
|
|
return false |
2241 |
|
|
} |
2242 |
|
|
if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { |
2243 |
|
|
if parser.buffer[parser.buffer_pos] == '+' { |
2244 |
|
|
chomping = +1 |
2245 |
|
|
} else { |
2246 |
|
|
chomping = -1 |
2247 |
|
|
} |
2248 |
|
|
skip(parser) |
2249 |
|
|
} |
2250 |
|
|
} |
2251 |
|
|
|
2252 |
|
|
// Eat whitespaces and comments to the end of the line. |
2253 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2254 |
|
|
return false |
2255 |
|
|
} |
2256 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) { |
2257 |
|
|
skip(parser) |
2258 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2259 |
|
|
return false |
2260 |
|
|
} |
2261 |
|
|
} |
2262 |
|
|
if parser.buffer[parser.buffer_pos] == '#' { |
2263 |
|
|
if !yaml_parser_scan_line_comment(parser, start_mark) { |
2264 |
|
|
return false |
2265 |
|
|
} |
2266 |
|
|
for !is_breakz(parser.buffer, parser.buffer_pos) { |
2267 |
|
|
skip(parser) |
2268 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2269 |
|
|
return false |
2270 |
|
|
} |
2271 |
|
|
} |
2272 |
|
|
} |
2273 |
|
|
|
2274 |
|
|
// Check if we are at the end of the line. |
2275 |
|
|
if !is_breakz(parser.buffer, parser.buffer_pos) { |
2276 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a block scalar", |
2277 |
|
|
start_mark, "did not find expected comment or line break") |
2278 |
|
|
return false |
2279 |
|
|
} |
2280 |
|
|
|
2281 |
|
|
// Eat a line break. |
2282 |
|
|
if is_break(parser.buffer, parser.buffer_pos) { |
2283 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2284 |
|
|
return false |
2285 |
|
|
} |
2286 |
|
|
skip_line(parser) |
2287 |
|
|
} |
2288 |
|
|
|
2289 |
|
|
end_mark := parser.mark |
2290 |
|
|
|
2291 |
|
|
// Set the indentation level if it was specified. |
2292 |
|
|
var indent int |
2293 |
|
|
if increment > 0 { |
2294 |
|
|
if parser.indent >= 0 { |
2295 |
|
|
indent = parser.indent + increment |
2296 |
|
|
} else { |
2297 |
|
|
indent = increment |
2298 |
|
|
} |
2299 |
|
|
} |
2300 |
|
|
|
2301 |
|
|
// Scan the leading line breaks and determine the indentation level if needed. |
2302 |
|
|
var s, leading_break, trailing_breaks []byte |
2303 |
|
|
if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { |
2304 |
|
|
return false |
2305 |
|
|
} |
2306 |
|
|
|
2307 |
|
|
// Scan the block scalar content. |
2308 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2309 |
|
|
return false |
2310 |
|
|
} |
2311 |
|
|
var leading_blank, trailing_blank bool |
2312 |
|
|
for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { |
2313 |
|
|
// We are at the beginning of a non-empty line. |
2314 |
|
|
|
2315 |
|
|
// Is it a trailing whitespace? |
2316 |
|
|
trailing_blank = is_blank(parser.buffer, parser.buffer_pos) |
2317 |
|
|
|
2318 |
|
|
// Check if we need to fold the leading line break. |
2319 |
|
|
if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { |
2320 |
|
|
// Do we need to join the lines by space? |
2321 |
|
|
if len(trailing_breaks) == 0 { |
2322 |
|
|
s = append(s, ' ') |
2323 |
|
|
} |
2324 |
|
|
} else { |
2325 |
|
|
s = append(s, leading_break...) |
2326 |
|
|
} |
2327 |
|
|
leading_break = leading_break[:0] |
2328 |
|
|
|
2329 |
|
|
// Append the remaining line breaks. |
2330 |
|
|
s = append(s, trailing_breaks...) |
2331 |
|
|
trailing_breaks = trailing_breaks[:0] |
2332 |
|
|
|
2333 |
|
|
// Is it a leading whitespace? |
2334 |
|
|
leading_blank = is_blank(parser.buffer, parser.buffer_pos) |
2335 |
|
|
|
2336 |
|
|
// Consume the current line. |
2337 |
|
|
for !is_breakz(parser.buffer, parser.buffer_pos) { |
2338 |
|
|
s = read(parser, s) |
2339 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2340 |
|
|
return false |
2341 |
|
|
} |
2342 |
|
|
} |
2343 |
|
|
|
2344 |
|
|
// Consume the line break. |
2345 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2346 |
|
|
return false |
2347 |
|
|
} |
2348 |
|
|
|
2349 |
|
|
leading_break = read_line(parser, leading_break) |
2350 |
|
|
|
2351 |
|
|
// Eat the following indentation spaces and line breaks. |
2352 |
|
|
if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { |
2353 |
|
|
return false |
2354 |
|
|
} |
2355 |
|
|
} |
2356 |
|
|
|
2357 |
|
|
// Chomp the tail. |
2358 |
|
|
if chomping != -1 { |
2359 |
|
|
s = append(s, leading_break...) |
2360 |
|
|
} |
2361 |
|
|
if chomping == 1 { |
2362 |
|
|
s = append(s, trailing_breaks...) |
2363 |
|
|
} |
2364 |
|
|
|
2365 |
|
|
// Create a token. |
2366 |
|
|
*token = yaml_token_t{ |
2367 |
|
|
typ: yaml_SCALAR_TOKEN, |
2368 |
|
|
start_mark: start_mark, |
2369 |
|
|
end_mark: end_mark, |
2370 |
|
|
value: s, |
2371 |
|
|
style: yaml_LITERAL_SCALAR_STYLE, |
2372 |
|
|
} |
2373 |
|
|
if !literal { |
2374 |
|
|
token.style = yaml_FOLDED_SCALAR_STYLE |
2375 |
|
|
} |
2376 |
|
|
return true |
2377 |
|
|
} |
2378 |
|
|
|
2379 |
|
|
// Scan indentation spaces and line breaks for a block scalar. Determine the |
2380 |
|
|
// indentation level if needed. |
2381 |
|
|
func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { |
2382 |
|
|
*end_mark = parser.mark |
2383 |
|
|
|
2384 |
|
|
// Eat the indentation spaces and line breaks. |
2385 |
|
|
max_indent := 0 |
2386 |
|
|
for { |
2387 |
|
|
// Eat the indentation spaces. |
2388 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2389 |
|
|
return false |
2390 |
|
|
} |
2391 |
|
|
for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { |
2392 |
|
|
skip(parser) |
2393 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2394 |
|
|
return false |
2395 |
|
|
} |
2396 |
|
|
} |
2397 |
|
|
if parser.mark.column > max_indent { |
2398 |
|
|
max_indent = parser.mark.column |
2399 |
|
|
} |
2400 |
|
|
|
2401 |
|
|
// Check for a tab character messing the indentation. |
2402 |
|
|
if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { |
2403 |
|
|
return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", |
2404 |
|
|
start_mark, "found a tab character where an indentation space is expected") |
2405 |
|
|
} |
2406 |
|
|
|
2407 |
|
|
// Have we found a non-empty line? |
2408 |
|
|
if !is_break(parser.buffer, parser.buffer_pos) { |
2409 |
|
|
break |
2410 |
|
|
} |
2411 |
|
|
|
2412 |
|
|
// Consume the line break. |
2413 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2414 |
|
|
return false |
2415 |
|
|
} |
2416 |
|
|
// [Go] Should really be returning breaks instead. |
2417 |
|
|
*breaks = read_line(parser, *breaks) |
2418 |
|
|
*end_mark = parser.mark |
2419 |
|
|
} |
2420 |
|
|
|
2421 |
|
|
// Determine the indentation level if needed. |
2422 |
|
|
if *indent == 0 { |
2423 |
|
|
*indent = max_indent |
2424 |
|
|
if *indent < parser.indent+1 { |
2425 |
|
|
*indent = parser.indent + 1 |
2426 |
|
|
} |
2427 |
|
|
if *indent < 1 { |
2428 |
|
|
*indent = 1 |
2429 |
|
|
} |
2430 |
|
|
} |
2431 |
|
|
return true |
2432 |
|
|
} |
2433 |
|
|
|
2434 |
|
|
// Scan a quoted scalar. |
2435 |
|
|
func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { |
2436 |
|
|
// Eat the left quote. |
2437 |
|
|
start_mark := parser.mark |
2438 |
|
|
skip(parser) |
2439 |
|
|
|
2440 |
|
|
// Consume the content of the quoted scalar. |
2441 |
|
|
var s, leading_break, trailing_breaks, whitespaces []byte |
2442 |
|
|
for { |
2443 |
|
|
// Check that there are no document indicators at the beginning of the line. |
2444 |
|
|
if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { |
2445 |
|
|
return false |
2446 |
|
|
} |
2447 |
|
|
|
2448 |
|
|
if parser.mark.column == 0 && |
2449 |
|
|
((parser.buffer[parser.buffer_pos+0] == '-' && |
2450 |
|
|
parser.buffer[parser.buffer_pos+1] == '-' && |
2451 |
|
|
parser.buffer[parser.buffer_pos+2] == '-') || |
2452 |
|
|
(parser.buffer[parser.buffer_pos+0] == '.' && |
2453 |
|
|
parser.buffer[parser.buffer_pos+1] == '.' && |
2454 |
|
|
parser.buffer[parser.buffer_pos+2] == '.')) && |
2455 |
|
|
is_blankz(parser.buffer, parser.buffer_pos+3) { |
2456 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", |
2457 |
|
|
start_mark, "found unexpected document indicator") |
2458 |
|
|
return false |
2459 |
|
|
} |
2460 |
|
|
|
2461 |
|
|
// Check for EOF. |
2462 |
|
|
if is_z(parser.buffer, parser.buffer_pos) { |
2463 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", |
2464 |
|
|
start_mark, "found unexpected end of stream") |
2465 |
|
|
return false |
2466 |
|
|
} |
2467 |
|
|
|
2468 |
|
|
// Consume non-blank characters. |
2469 |
|
|
leading_blanks := false |
2470 |
|
|
for !is_blankz(parser.buffer, parser.buffer_pos) { |
2471 |
|
|
if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { |
2472 |
|
|
// Is is an escaped single quote. |
2473 |
|
|
s = append(s, '\'') |
2474 |
|
|
skip(parser) |
2475 |
|
|
skip(parser) |
2476 |
|
|
|
2477 |
|
|
} else if single && parser.buffer[parser.buffer_pos] == '\'' { |
2478 |
|
|
// It is a right single quote. |
2479 |
|
|
break |
2480 |
|
|
} else if !single && parser.buffer[parser.buffer_pos] == '"' { |
2481 |
|
|
// It is a right double quote. |
2482 |
|
|
break |
2483 |
|
|
|
2484 |
|
|
} else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { |
2485 |
|
|
// It is an escaped line break. |
2486 |
|
|
if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { |
2487 |
|
|
return false |
2488 |
|
|
} |
2489 |
|
|
skip(parser) |
2490 |
|
|
skip_line(parser) |
2491 |
|
|
leading_blanks = true |
2492 |
|
|
break |
2493 |
|
|
|
2494 |
|
|
} else if !single && parser.buffer[parser.buffer_pos] == '\\' { |
2495 |
|
|
// It is an escape sequence. |
2496 |
|
|
code_length := 0 |
2497 |
|
|
|
2498 |
|
|
// Check the escape character. |
2499 |
|
|
switch parser.buffer[parser.buffer_pos+1] { |
2500 |
|
|
case '0': |
2501 |
|
|
s = append(s, 0) |
2502 |
|
|
case 'a': |
2503 |
|
|
s = append(s, '\x07') |
2504 |
|
|
case 'b': |
2505 |
|
|
s = append(s, '\x08') |
2506 |
|
|
case 't', '\t': |
2507 |
|
|
s = append(s, '\x09') |
2508 |
|
|
case 'n': |
2509 |
|
|
s = append(s, '\x0A') |
2510 |
|
|
case 'v': |
2511 |
|
|
s = append(s, '\x0B') |
2512 |
|
|
case 'f': |
2513 |
|
|
s = append(s, '\x0C') |
2514 |
|
|
case 'r': |
2515 |
|
|
s = append(s, '\x0D') |
2516 |
|
|
case 'e': |
2517 |
|
|
s = append(s, '\x1B') |
2518 |
|
|
case ' ': |
2519 |
|
|
s = append(s, '\x20') |
2520 |
|
|
case '"': |
2521 |
|
|
s = append(s, '"') |
2522 |
|
|
case '\'': |
2523 |
|
|
s = append(s, '\'') |
2524 |
|
|
case '\\': |
2525 |
|
|
s = append(s, '\\') |
2526 |
|
|
case 'N': // NEL (#x85) |
2527 |
|
|
s = append(s, '\xC2') |
2528 |
|
|
s = append(s, '\x85') |
2529 |
|
|
case '_': // #xA0 |
2530 |
|
|
s = append(s, '\xC2') |
2531 |
|
|
s = append(s, '\xA0') |
2532 |
|
|
case 'L': // LS (#x2028) |
2533 |
|
|
s = append(s, '\xE2') |
2534 |
|
|
s = append(s, '\x80') |
2535 |
|
|
s = append(s, '\xA8') |
2536 |
|
|
case 'P': // PS (#x2029) |
2537 |
|
|
s = append(s, '\xE2') |
2538 |
|
|
s = append(s, '\x80') |
2539 |
|
|
s = append(s, '\xA9') |
2540 |
|
|
case 'x': |
2541 |
|
|
code_length = 2 |
2542 |
|
|
case 'u': |
2543 |
|
|
code_length = 4 |
2544 |
|
|
case 'U': |
2545 |
|
|
code_length = 8 |
2546 |
|
|
default: |
2547 |
|
|
yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", |
2548 |
|
|
start_mark, "found unknown escape character") |
2549 |
|
|
return false |
2550 |
|
|
} |
2551 |
|
|
|
2552 |
|
|
skip(parser) |
2553 |
|
|
skip(parser) |
2554 |
|
|
|
2555 |
|
|
// Consume an arbitrary escape code. |
2556 |
|
|
if code_length > 0 { |
2557 |
|
|
var value int |
2558 |
|
|
|
2559 |
|
|
// Scan the character value. |
2560 |
|
|
if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { |
2561 |
|
|
return false |
2562 |
|
|
} |
2563 |
|
|
for k := 0; k < code_length; k++ { |
2564 |
|
|
if !is_hex(parser.buffer, parser.buffer_pos+k) { |
2565 |
|
|
yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", |
2566 |
|
|
start_mark, "did not find expected hexdecimal number") |
2567 |
|
|
return false |
2568 |
|
|
} |
2569 |
|
|
value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) |
2570 |
|
|
} |
2571 |
|
|
|
2572 |
|
|
// Check the value and write the character. |
2573 |
|
|
if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { |
2574 |
|
|
yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", |
2575 |
|
|
start_mark, "found invalid Unicode character escape code") |
2576 |
|
|
return false |
2577 |
|
|
} |
2578 |
|
|
if value <= 0x7F { |
2579 |
|
|
s = append(s, byte(value)) |
2580 |
|
|
} else if value <= 0x7FF { |
2581 |
|
|
s = append(s, byte(0xC0+(value>>6))) |
2582 |
|
|
s = append(s, byte(0x80+(value&0x3F))) |
2583 |
|
|
} else if value <= 0xFFFF { |
2584 |
|
|
s = append(s, byte(0xE0+(value>>12))) |
2585 |
|
|
s = append(s, byte(0x80+((value>>6)&0x3F))) |
2586 |
|
|
s = append(s, byte(0x80+(value&0x3F))) |
2587 |
|
|
} else { |
2588 |
|
|
s = append(s, byte(0xF0+(value>>18))) |
2589 |
|
|
s = append(s, byte(0x80+((value>>12)&0x3F))) |
2590 |
|
|
s = append(s, byte(0x80+((value>>6)&0x3F))) |
2591 |
|
|
s = append(s, byte(0x80+(value&0x3F))) |
2592 |
|
|
} |
2593 |
|
|
|
2594 |
|
|
// Advance the pointer. |
2595 |
|
|
for k := 0; k < code_length; k++ { |
2596 |
|
|
skip(parser) |
2597 |
|
|
} |
2598 |
|
|
} |
2599 |
|
|
} else { |
2600 |
|
|
// It is a non-escaped non-blank character. |
2601 |
|
|
s = read(parser, s) |
2602 |
|
|
} |
2603 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2604 |
|
|
return false |
2605 |
|
|
} |
2606 |
|
|
} |
2607 |
|
|
|
2608 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2609 |
|
|
return false |
2610 |
|
|
} |
2611 |
|
|
|
2612 |
|
|
// Check if we are at the end of the scalar. |
2613 |
|
|
if single { |
2614 |
|
|
if parser.buffer[parser.buffer_pos] == '\'' { |
2615 |
|
|
break |
2616 |
|
|
} |
2617 |
|
|
} else { |
2618 |
|
|
if parser.buffer[parser.buffer_pos] == '"' { |
2619 |
|
|
break |
2620 |
|
|
} |
2621 |
|
|
} |
2622 |
|
|
|
2623 |
|
|
// Consume blank characters. |
2624 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { |
2625 |
|
|
if is_blank(parser.buffer, parser.buffer_pos) { |
2626 |
|
|
// Consume a space or a tab character. |
2627 |
|
|
if !leading_blanks { |
2628 |
|
|
whitespaces = read(parser, whitespaces) |
2629 |
|
|
} else { |
2630 |
|
|
skip(parser) |
2631 |
|
|
} |
2632 |
|
|
} else { |
2633 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2634 |
|
|
return false |
2635 |
|
|
} |
2636 |
|
|
|
2637 |
|
|
// Check if it is a first line break. |
2638 |
|
|
if !leading_blanks { |
2639 |
|
|
whitespaces = whitespaces[:0] |
2640 |
|
|
leading_break = read_line(parser, leading_break) |
2641 |
|
|
leading_blanks = true |
2642 |
|
|
} else { |
2643 |
|
|
trailing_breaks = read_line(parser, trailing_breaks) |
2644 |
|
|
} |
2645 |
|
|
} |
2646 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2647 |
|
|
return false |
2648 |
|
|
} |
2649 |
|
|
} |
2650 |
|
|
|
2651 |
|
|
// Join the whitespaces or fold line breaks. |
2652 |
|
|
if leading_blanks { |
2653 |
|
|
// Do we need to fold line breaks? |
2654 |
|
|
if len(leading_break) > 0 && leading_break[0] == '\n' { |
2655 |
|
|
if len(trailing_breaks) == 0 { |
2656 |
|
|
s = append(s, ' ') |
2657 |
|
|
} else { |
2658 |
|
|
s = append(s, trailing_breaks...) |
2659 |
|
|
} |
2660 |
|
|
} else { |
2661 |
|
|
s = append(s, leading_break...) |
2662 |
|
|
s = append(s, trailing_breaks...) |
2663 |
|
|
} |
2664 |
|
|
trailing_breaks = trailing_breaks[:0] |
2665 |
|
|
leading_break = leading_break[:0] |
2666 |
|
|
} else { |
2667 |
|
|
s = append(s, whitespaces...) |
2668 |
|
|
whitespaces = whitespaces[:0] |
2669 |
|
|
} |
2670 |
|
|
} |
2671 |
|
|
|
2672 |
|
|
// Eat the right quote. |
2673 |
|
|
skip(parser) |
2674 |
|
|
end_mark := parser.mark |
2675 |
|
|
|
2676 |
|
|
// Create a token. |
2677 |
|
|
*token = yaml_token_t{ |
2678 |
|
|
typ: yaml_SCALAR_TOKEN, |
2679 |
|
|
start_mark: start_mark, |
2680 |
|
|
end_mark: end_mark, |
2681 |
|
|
value: s, |
2682 |
|
|
style: yaml_SINGLE_QUOTED_SCALAR_STYLE, |
2683 |
|
|
} |
2684 |
|
|
if !single { |
2685 |
|
|
token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE |
2686 |
|
|
} |
2687 |
|
|
return true |
2688 |
|
|
} |
2689 |
|
|
|
2690 |
|
|
// Scan a plain scalar. |
2691 |
|
|
func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { |
2692 |
|
|
|
2693 |
|
|
var s, leading_break, trailing_breaks, whitespaces []byte |
2694 |
|
|
var leading_blanks bool |
2695 |
|
|
var indent = parser.indent + 1 |
2696 |
|
|
|
2697 |
|
|
start_mark := parser.mark |
2698 |
|
|
end_mark := parser.mark |
2699 |
|
|
|
2700 |
|
|
// Consume the content of the plain scalar. |
2701 |
|
|
for { |
2702 |
|
|
// Check for a document indicator. |
2703 |
|
|
if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { |
2704 |
|
|
return false |
2705 |
|
|
} |
2706 |
|
|
if parser.mark.column == 0 && |
2707 |
|
|
((parser.buffer[parser.buffer_pos+0] == '-' && |
2708 |
|
|
parser.buffer[parser.buffer_pos+1] == '-' && |
2709 |
|
|
parser.buffer[parser.buffer_pos+2] == '-') || |
2710 |
|
|
(parser.buffer[parser.buffer_pos+0] == '.' && |
2711 |
|
|
parser.buffer[parser.buffer_pos+1] == '.' && |
2712 |
|
|
parser.buffer[parser.buffer_pos+2] == '.')) && |
2713 |
|
|
is_blankz(parser.buffer, parser.buffer_pos+3) { |
2714 |
|
|
break |
2715 |
|
|
} |
2716 |
|
|
|
2717 |
|
|
// Check for a comment. |
2718 |
|
|
if parser.buffer[parser.buffer_pos] == '#' { |
2719 |
|
|
break |
2720 |
|
|
} |
2721 |
|
|
|
2722 |
|
|
// Consume non-blank characters. |
2723 |
|
|
for !is_blankz(parser.buffer, parser.buffer_pos) { |
2724 |
|
|
|
2725 |
|
|
// Check for indicators that may end a plain scalar. |
2726 |
|
|
if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || |
2727 |
|
|
(parser.flow_level > 0 && |
2728 |
|
|
(parser.buffer[parser.buffer_pos] == ',' || |
2729 |
|
|
parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || |
2730 |
|
|
parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || |
2731 |
|
|
parser.buffer[parser.buffer_pos] == '}')) { |
2732 |
|
|
break |
2733 |
|
|
} |
2734 |
|
|
|
2735 |
|
|
// Check if we need to join whitespaces and breaks. |
2736 |
|
|
if leading_blanks || len(whitespaces) > 0 { |
2737 |
|
|
if leading_blanks { |
2738 |
|
|
// Do we need to fold line breaks? |
2739 |
|
|
if leading_break[0] == '\n' { |
2740 |
|
|
if len(trailing_breaks) == 0 { |
2741 |
|
|
s = append(s, ' ') |
2742 |
|
|
} else { |
2743 |
|
|
s = append(s, trailing_breaks...) |
2744 |
|
|
} |
2745 |
|
|
} else { |
2746 |
|
|
s = append(s, leading_break...) |
2747 |
|
|
s = append(s, trailing_breaks...) |
2748 |
|
|
} |
2749 |
|
|
trailing_breaks = trailing_breaks[:0] |
2750 |
|
|
leading_break = leading_break[:0] |
2751 |
|
|
leading_blanks = false |
2752 |
|
|
} else { |
2753 |
|
|
s = append(s, whitespaces...) |
2754 |
|
|
whitespaces = whitespaces[:0] |
2755 |
|
|
} |
2756 |
|
|
} |
2757 |
|
|
|
2758 |
|
|
// Copy the character. |
2759 |
|
|
s = read(parser, s) |
2760 |
|
|
|
2761 |
|
|
end_mark = parser.mark |
2762 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2763 |
|
|
return false |
2764 |
|
|
} |
2765 |
|
|
} |
2766 |
|
|
|
2767 |
|
|
// Is it the end? |
2768 |
|
|
if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { |
2769 |
|
|
break |
2770 |
|
|
} |
2771 |
|
|
|
2772 |
|
|
// Consume blank characters. |
2773 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2774 |
|
|
return false |
2775 |
|
|
} |
2776 |
|
|
|
2777 |
|
|
for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { |
2778 |
|
|
if is_blank(parser.buffer, parser.buffer_pos) { |
2779 |
|
|
|
2780 |
|
|
// Check for tab characters that abuse indentation. |
2781 |
|
|
if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { |
2782 |
|
|
yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", |
2783 |
|
|
start_mark, "found a tab character that violates indentation") |
2784 |
|
|
return false |
2785 |
|
|
} |
2786 |
|
|
|
2787 |
|
|
// Consume a space or a tab character. |
2788 |
|
|
if !leading_blanks { |
2789 |
|
|
whitespaces = read(parser, whitespaces) |
2790 |
|
|
} else { |
2791 |
|
|
skip(parser) |
2792 |
|
|
} |
2793 |
|
|
} else { |
2794 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2795 |
|
|
return false |
2796 |
|
|
} |
2797 |
|
|
|
2798 |
|
|
// Check if it is a first line break. |
2799 |
|
|
if !leading_blanks { |
2800 |
|
|
whitespaces = whitespaces[:0] |
2801 |
|
|
leading_break = read_line(parser, leading_break) |
2802 |
|
|
leading_blanks = true |
2803 |
|
|
} else { |
2804 |
|
|
trailing_breaks = read_line(parser, trailing_breaks) |
2805 |
|
|
} |
2806 |
|
|
} |
2807 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2808 |
|
|
return false |
2809 |
|
|
} |
2810 |
|
|
} |
2811 |
|
|
|
2812 |
|
|
// Check indentation level. |
2813 |
|
|
if parser.flow_level == 0 && parser.mark.column < indent { |
2814 |
|
|
break |
2815 |
|
|
} |
2816 |
|
|
} |
2817 |
|
|
|
2818 |
|
|
// Create a token. |
2819 |
|
|
*token = yaml_token_t{ |
2820 |
|
|
typ: yaml_SCALAR_TOKEN, |
2821 |
|
|
start_mark: start_mark, |
2822 |
|
|
end_mark: end_mark, |
2823 |
|
|
value: s, |
2824 |
|
|
style: yaml_PLAIN_SCALAR_STYLE, |
2825 |
|
|
} |
2826 |
|
|
|
2827 |
|
|
// Note that we change the 'simple_key_allowed' flag. |
2828 |
|
|
if leading_blanks { |
2829 |
|
|
parser.simple_key_allowed = true |
2830 |
|
|
} |
2831 |
|
|
return true |
2832 |
|
|
} |
2833 |
|
|
|
2834 |
|
|
func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool { |
2835 |
|
|
if parser.newlines > 0 { |
2836 |
|
|
return true |
2837 |
|
|
} |
2838 |
|
|
|
2839 |
|
|
var start_mark yaml_mark_t |
2840 |
|
|
var text []byte |
2841 |
|
|
|
2842 |
|
|
for peek := 0; peek < 512; peek++ { |
2843 |
|
|
if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { |
2844 |
|
|
break |
2845 |
|
|
} |
2846 |
|
|
if is_blank(parser.buffer, parser.buffer_pos+peek) { |
2847 |
|
|
continue |
2848 |
|
|
} |
2849 |
|
|
if parser.buffer[parser.buffer_pos+peek] == '#' { |
2850 |
|
|
seen := parser.mark.index+peek |
2851 |
|
|
for { |
2852 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
2853 |
|
|
return false |
2854 |
|
|
} |
2855 |
|
|
if is_breakz(parser.buffer, parser.buffer_pos) { |
2856 |
|
|
if parser.mark.index >= seen { |
2857 |
|
|
break |
2858 |
|
|
} |
2859 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
2860 |
|
|
return false |
2861 |
|
|
} |
2862 |
|
|
skip_line(parser) |
2863 |
|
|
} else if parser.mark.index >= seen { |
2864 |
|
|
if len(text) == 0 { |
2865 |
|
|
start_mark = parser.mark |
2866 |
|
|
} |
2867 |
|
|
text = read(parser, text) |
2868 |
|
|
} else { |
2869 |
|
|
skip(parser) |
2870 |
|
|
} |
2871 |
|
|
} |
2872 |
|
|
} |
2873 |
|
|
break |
2874 |
|
|
} |
2875 |
|
|
if len(text) > 0 { |
2876 |
|
|
parser.comments = append(parser.comments, yaml_comment_t{ |
2877 |
|
|
token_mark: token_mark, |
2878 |
|
|
start_mark: start_mark, |
2879 |
|
|
line: text, |
2880 |
|
|
}) |
2881 |
|
|
} |
2882 |
|
|
return true |
2883 |
|
|
} |
2884 |
|
|
|
2885 |
|
|
func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool { |
2886 |
|
|
token := parser.tokens[len(parser.tokens)-1] |
2887 |
|
|
|
2888 |
|
|
if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 { |
2889 |
|
|
token = parser.tokens[len(parser.tokens)-2] |
2890 |
|
|
} |
2891 |
|
|
|
2892 |
|
|
var token_mark = token.start_mark |
2893 |
|
|
var start_mark yaml_mark_t |
2894 |
|
|
var next_indent = parser.indent |
2895 |
|
|
if next_indent < 0 { |
2896 |
|
|
next_indent = 0 |
2897 |
|
|
} |
2898 |
|
|
|
2899 |
|
|
var recent_empty = false |
2900 |
|
|
var first_empty = parser.newlines <= 1 |
2901 |
|
|
|
2902 |
|
|
var line = parser.mark.line |
2903 |
|
|
var column = parser.mark.column |
2904 |
|
|
|
2905 |
|
|
var text []byte |
2906 |
|
|
|
2907 |
|
|
// The foot line is the place where a comment must start to |
2908 |
|
|
// still be considered as a foot of the prior content. |
2909 |
|
|
// If there's some content in the currently parsed line, then |
2910 |
|
|
// the foot is the line below it. |
2911 |
|
|
var foot_line = -1 |
2912 |
|
|
if scan_mark.line > 0 { |
2913 |
|
|
foot_line = parser.mark.line-parser.newlines+1 |
2914 |
|
|
if parser.newlines == 0 && parser.mark.column > 1 { |
2915 |
|
|
foot_line++ |
2916 |
|
|
} |
2917 |
|
|
} |
2918 |
|
|
|
2919 |
|
|
var peek = 0 |
2920 |
|
|
for ; peek < 512; peek++ { |
2921 |
|
|
if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { |
2922 |
|
|
break |
2923 |
|
|
} |
2924 |
|
|
column++ |
2925 |
|
|
if is_blank(parser.buffer, parser.buffer_pos+peek) { |
2926 |
|
|
continue |
2927 |
|
|
} |
2928 |
|
|
c := parser.buffer[parser.buffer_pos+peek] |
2929 |
|
|
var close_flow = parser.flow_level > 0 && (c == ']' || c == '}') |
2930 |
|
|
if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) { |
2931 |
|
|
// Got line break or terminator. |
2932 |
|
|
if close_flow || !recent_empty { |
2933 |
|
|
if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) { |
2934 |
|
|
// This is the first empty line and there were no empty lines before, |
2935 |
|
|
// so this initial part of the comment is a foot of the prior token |
2936 |
|
|
// instead of being a head for the following one. Split it up. |
2937 |
|
|
// Alternatively, this might also be the last comment inside a flow |
2938 |
|
|
// scope, so it must be a footer. |
2939 |
|
|
if len(text) > 0 { |
2940 |
|
|
if start_mark.column-1 < next_indent { |
2941 |
|
|
// If dedented it's unrelated to the prior token. |
2942 |
|
|
token_mark = start_mark |
2943 |
|
|
} |
2944 |
|
|
parser.comments = append(parser.comments, yaml_comment_t{ |
2945 |
|
|
scan_mark: scan_mark, |
2946 |
|
|
token_mark: token_mark, |
2947 |
|
|
start_mark: start_mark, |
2948 |
|
|
end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, |
2949 |
|
|
foot: text, |
2950 |
|
|
}) |
2951 |
|
|
scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} |
2952 |
|
|
token_mark = scan_mark |
2953 |
|
|
text = nil |
2954 |
|
|
} |
2955 |
|
|
} else { |
2956 |
|
|
if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 { |
2957 |
|
|
text = append(text, '\n') |
2958 |
|
|
} |
2959 |
|
|
} |
2960 |
|
|
} |
2961 |
|
|
if !is_break(parser.buffer, parser.buffer_pos+peek) { |
2962 |
|
|
break |
2963 |
|
|
} |
2964 |
|
|
first_empty = false |
2965 |
|
|
recent_empty = true |
2966 |
|
|
column = 0 |
2967 |
|
|
line++ |
2968 |
|
|
continue |
2969 |
|
|
} |
2970 |
|
|
|
2971 |
|
|
if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) { |
2972 |
|
|
// The comment at the different indentation is a foot of the |
2973 |
|
|
// preceding data rather than a head of the upcoming one. |
2974 |
|
|
parser.comments = append(parser.comments, yaml_comment_t{ |
2975 |
|
|
scan_mark: scan_mark, |
2976 |
|
|
token_mark: token_mark, |
2977 |
|
|
start_mark: start_mark, |
2978 |
|
|
end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, |
2979 |
|
|
foot: text, |
2980 |
|
|
}) |
2981 |
|
|
scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} |
2982 |
|
|
token_mark = scan_mark |
2983 |
|
|
text = nil |
2984 |
|
|
} |
2985 |
|
|
|
2986 |
|
|
if parser.buffer[parser.buffer_pos+peek] != '#' { |
2987 |
|
|
break |
2988 |
|
|
} |
2989 |
|
|
|
2990 |
|
|
if len(text) == 0 { |
2991 |
|
|
start_mark = yaml_mark_t{parser.mark.index + peek, line, column} |
2992 |
|
|
} else { |
2993 |
|
|
text = append(text, '\n') |
2994 |
|
|
} |
2995 |
|
|
|
2996 |
|
|
recent_empty = false |
2997 |
|
|
|
2998 |
|
|
// Consume until after the consumed comment line. |
2999 |
|
|
seen := parser.mark.index+peek |
3000 |
|
|
for { |
3001 |
|
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { |
3002 |
|
|
return false |
3003 |
|
|
} |
3004 |
|
|
if is_breakz(parser.buffer, parser.buffer_pos) { |
3005 |
|
|
if parser.mark.index >= seen { |
3006 |
|
|
break |
3007 |
|
|
} |
3008 |
|
|
if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { |
3009 |
|
|
return false |
3010 |
|
|
} |
3011 |
|
|
skip_line(parser) |
3012 |
|
|
} else if parser.mark.index >= seen { |
3013 |
|
|
text = read(parser, text) |
3014 |
|
|
} else { |
3015 |
|
|
skip(parser) |
3016 |
|
|
} |
3017 |
|
|
} |
3018 |
|
|
|
3019 |
|
|
peek = 0 |
3020 |
|
|
column = 0 |
3021 |
|
|
line = parser.mark.line |
3022 |
|
|
next_indent = parser.indent |
3023 |
|
|
if next_indent < 0 { |
3024 |
|
|
next_indent = 0 |
3025 |
|
|
} |
3026 |
|
|
} |
3027 |
|
|
|
3028 |
|
|
if len(text) > 0 { |
3029 |
|
|
parser.comments = append(parser.comments, yaml_comment_t{ |
3030 |
|
|
scan_mark: scan_mark, |
3031 |
|
|
token_mark: start_mark, |
3032 |
|
|
start_mark: start_mark, |
3033 |
|
|
end_mark: yaml_mark_t{parser.mark.index + peek - 1, line, column}, |
3034 |
|
|
head: text, |
3035 |
|
|
}) |
3036 |
|
|
} |
3037 |
|
|
return true |
3038 |
|
|
} |