omextra 0.0.0.dev472__py3-none-any.whl → 0.0.0.dev485__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2332 @@
1
+ # ruff: noqa: UP006 UP007 UP043 UP045
2
+ # @omlish-lite
3
+ import copy
4
+ import dataclasses as dc
5
+ import enum
6
+ import typing as ta
7
+
8
+ from omlish.lite.check import check
9
+ from omlish.lite.dataclasses import dataclass_field_required
10
+
11
+ from . import ast
12
+ from .errors import YamlError
13
+ from .errors import YamlErrorOr
14
+ from .errors import yaml_error
15
+ from .scanning import yaml_tokenize
16
+ from .tokens import YamlReservedTagKeywords
17
+ from .tokens import YamlToken
18
+ from .tokens import YamlTokens
19
+ from .tokens import YamlTokenType
20
+ from .tokens import new_yaml_token
21
+
22
+
23
+ ##
24
+
25
+
26
+ # context context at parsing
27
+ @dc.dataclass()
28
+ class YamlParsingContext:
29
+ token_ref: ta.Optional['YamlParseTokenRef'] = None
30
+ path: str = dc.field(default_factory=dataclass_field_required('path'))
31
+ is_flow: bool = False
32
+
33
+ def current_token(self) -> ta.Optional['YamlParseToken']:
34
+ ref = check.not_none(self.token_ref)
35
+
36
+ if ref.idx >= ref.size:
37
+ return None
38
+
39
+ return ref.tokens[ref.idx]
40
+
41
+ def is_comment(self) -> bool:
42
+ return YamlParseToken.type(self.current_token()) == YamlTokenType.COMMENT
43
+
44
+ def next_token(self) -> ta.Optional['YamlParseToken']:
45
+ ref = check.not_none(self.token_ref)
46
+
47
+ if ref.idx + 1 >= ref.size:
48
+ return None
49
+
50
+ return ref.tokens[ref.idx + 1]
51
+
52
+ def next_not_comment_token(self) -> ta.Optional['YamlParseToken']:
53
+ ref = check.not_none(self.token_ref)
54
+
55
+ for i in range(ref.idx + 1, ref.size):
56
+ tk = ref.tokens[i]
57
+ if tk.type() == YamlTokenType.COMMENT:
58
+ continue
59
+ return tk
60
+
61
+ return None
62
+
63
+ def is_token_not_found(self) -> bool:
64
+ return self.current_token() is None
65
+
66
+ def with_group(self, g: 'YamlParseTokenGroup') -> 'YamlParsingContext':
67
+ ctx = copy.copy(self)
68
+ ctx.token_ref = YamlParseTokenRef(
69
+ tokens=g.tokens,
70
+ size=len(g.tokens),
71
+ )
72
+ return ctx
73
+
74
+ def with_child(self, path: str) -> 'YamlParsingContext':
75
+ ctx = copy.copy(self)
76
+ ctx.path = self.path + '.' + normalize_path(path)
77
+ return ctx
78
+
79
+ def with_index(self, idx: int) -> 'YamlParsingContext':
80
+ ctx = copy.copy(self)
81
+ ctx.path = self.path + '[' + str(idx) + ']'
82
+ return ctx
83
+
84
+ def with_flow(self, is_flow: bool) -> 'YamlParsingContext':
85
+ ctx = copy.copy(self)
86
+ ctx.is_flow = is_flow
87
+ return ctx
88
+
89
+ @staticmethod
90
+ def new() -> 'YamlParsingContext':
91
+ return YamlParsingContext(
92
+ path='$',
93
+ )
94
+
95
+ def go_next(self) -> None:
96
+ ref = check.not_none(self.token_ref)
97
+ if ref.size <= ref.idx + 1:
98
+ ref.idx = ref.size
99
+ else:
100
+ ref.idx += 1
101
+
102
+ def next(self) -> bool:
103
+ return check.not_none(self.token_ref).idx < check.not_none(self.token_ref).size
104
+
105
+ def insert_null_token(self, tk: 'YamlParseToken') -> 'YamlParseToken':
106
+ null_token = self.create_implicit_null_token(tk)
107
+ self.insert_token(null_token)
108
+ self.go_next()
109
+
110
+ return null_token
111
+
112
+ def add_null_value_token(self, tk: 'YamlParseToken') -> 'YamlParseToken':
113
+ null_token = self.create_implicit_null_token(tk)
114
+ raw_tk = null_token.raw_token()
115
+
116
+ # add space for map or sequence value.
117
+ check.not_none(raw_tk).position.column += 1
118
+
119
+ self.add_token(null_token)
120
+ self.go_next()
121
+
122
+ return null_token
123
+
124
+ def create_implicit_null_token(self, base: 'YamlParseToken') -> 'YamlParseToken':
125
+ pos = copy.copy(check.not_none(base.raw_token()).position)
126
+ pos.column += 1
127
+ tk = new_yaml_token('null', ' null', pos)
128
+ tk.type = YamlTokenType.IMPLICIT_NULL
129
+ return YamlParseToken(token=tk)
130
+
131
+ def insert_token(self, tk: 'YamlParseToken') -> None:
132
+ ref = check.not_none(self.token_ref)
133
+ idx = ref.idx
134
+ if ref.size < idx:
135
+ return
136
+
137
+ if ref.size == idx:
138
+ cur_token = ref.tokens[ref.size - 1]
139
+ check.not_none(tk.raw_token()).next = cur_token.raw_token()
140
+ check.not_none(cur_token.raw_token()).prev = tk.raw_token()
141
+
142
+ ref.tokens.append(tk)
143
+ ref.size = len(ref.tokens)
144
+ return
145
+
146
+ cur_token = ref.tokens[idx]
147
+ check.not_none(tk.raw_token()).next = cur_token.raw_token()
148
+ check.not_none(cur_token.raw_token()).prev = tk.raw_token()
149
+
150
+ ref.tokens = [*ref.tokens[:idx + 1], *ref.tokens[idx:]]
151
+ ref.tokens[idx] = tk
152
+ ref.size = len(ref.tokens)
153
+
154
+ def add_token(self, tk: 'YamlParseToken') -> None:
155
+ ref = check.not_none(self.token_ref)
156
+ last_tk = check.not_none(ref.tokens[ref.size - 1])
157
+ if last_tk.group is not None:
158
+ last_tk = check.not_none(last_tk.group.last())
159
+
160
+ check.not_none(last_tk.raw_token()).next = tk.raw_token()
161
+ check.not_none(tk.raw_token()).prev = last_tk.raw_token()
162
+
163
+ ref.tokens.append(tk)
164
+ ref.size = len(ref.tokens)
165
+
166
+
167
+ @dc.dataclass()
168
+ class YamlParseTokenRef:
169
+ tokens: ta.List['YamlParseToken']
170
+ size: int
171
+ idx: int = 0
172
+
173
+
174
+ ##
175
+
176
+
177
+ PATH_SPECIAL_CHARS = (
178
+ '$',
179
+ '*',
180
+ '.',
181
+ '[',
182
+ ']',
183
+ )
184
+
185
+
186
+ def contains_path_special_char(path: str) -> bool:
187
+ return any(char in path for char in PATH_SPECIAL_CHARS)
188
+
189
+
190
+ def normalize_path(path: str) -> str:
191
+ if contains_path_special_char(path):
192
+ return f"'{path}'"
193
+
194
+ return path
195
+
196
+
197
+ ##
198
+
199
+
200
+ # Option represents parser's option.
201
+ Option = ta.Callable[['YamlParser'], None] # ta.TypeAlias # omlish-amalg-typing-no-move
202
+
203
+
204
+ # AllowDuplicateMapKey allow the use of keys with the same name in the same map, but by default, this is not permitted.
205
+ def allow_duplicate_map_key() -> Option:
206
+ def fn(p: 'YamlParser') -> None:
207
+ p.allow_duplicate_map_key = True
208
+
209
+ return fn
210
+
211
+
212
+ ##
213
+
214
+
215
+ class YamlParseTokenGroupType(enum.Enum):
216
+ NONE = enum.auto()
217
+ DIRECTIVE = enum.auto()
218
+ DIRECTIVE_NAME = enum.auto()
219
+ DOCUMENT = enum.auto()
220
+ DOCUMENT_BODY = enum.auto()
221
+ ANCHOR = enum.auto()
222
+ ANCHOR_NAME = enum.auto()
223
+ ALIAS = enum.auto()
224
+ LITERAL = enum.auto()
225
+ FOLDED = enum.auto()
226
+ SCALAR_TAG = enum.auto()
227
+ MAP_KEY = enum.auto()
228
+ MAP_KEY_VALUE = enum.auto()
229
+
230
+
231
+ @dc.dataclass()
232
+ class YamlParseToken:
233
+ token: ta.Optional[YamlToken] = None
234
+ group: ta.Optional['YamlParseTokenGroup'] = None
235
+ line_comment: ta.Optional[YamlToken] = None
236
+
237
+ def raw_token(self: ta.Optional['YamlParseToken']) -> ta.Optional[YamlToken]:
238
+ if self is None:
239
+ return None
240
+ if self.token is not None:
241
+ return self.token
242
+ return check.not_none(self.group).raw_token()
243
+
244
+ def type(self: ta.Optional['YamlParseToken']) -> YamlTokenType:
245
+ if self is None:
246
+ return YamlTokenType.UNKNOWN
247
+ if self.token is not None:
248
+ return self.token.type
249
+ return check.not_none(self.group).token_type()
250
+
251
+ def group_type(self: ta.Optional['YamlParseToken']) -> YamlParseTokenGroupType:
252
+ if self is None:
253
+ return YamlParseTokenGroupType.NONE
254
+ if self.token is not None:
255
+ return YamlParseTokenGroupType.NONE
256
+ return check.not_none(self.group).type
257
+
258
+ def line(self: ta.Optional['YamlParseToken']) -> int:
259
+ if self is None:
260
+ return 0
261
+ if self.token is not None:
262
+ return self.token.position.line
263
+ return check.not_none(self.group).line()
264
+
265
+ def column(self: ta.Optional['YamlParseToken']) -> int:
266
+ if self is None:
267
+ return 0
268
+ if self.token is not None:
269
+ return self.token.position.column
270
+ return check.not_none(self.group).column()
271
+
272
+ def set_group_type(self, typ: YamlParseTokenGroupType) -> None:
273
+ if self.group is None:
274
+ return
275
+ self.group.type = typ
276
+
277
+
278
+ ##
279
+
280
+
281
+ @dc.dataclass()
282
+ class YamlParseTokenGroup:
283
+ type: YamlParseTokenGroupType = YamlParseTokenGroupType.NONE
284
+ tokens: ta.List[YamlParseToken] = dc.field(default_factory=dataclass_field_required('tokens'))
285
+
286
+ def first(self) -> ta.Optional[YamlParseToken]:
287
+ if len(self.tokens) == 0:
288
+ return None
289
+ return self.tokens[0]
290
+
291
+ def last(self) -> ta.Optional[YamlParseToken]:
292
+ if len(self.tokens) == 0:
293
+ return None
294
+ return self.tokens[len(self.tokens) - 1]
295
+
296
+ def raw_token(self) -> ta.Optional[YamlToken]:
297
+ if len(self.tokens) == 0:
298
+ return None
299
+ return self.tokens[0].raw_token()
300
+
301
+ def line(self) -> int:
302
+ if len(self.tokens) == 0:
303
+ return 0
304
+ return self.tokens[0].line()
305
+
306
+ def column(self) -> int:
307
+ if len(self.tokens) == 0:
308
+ return 0
309
+ return self.tokens[0].column()
310
+
311
+ def token_type(self) -> YamlTokenType:
312
+ if len(self.tokens) == 0:
313
+ return YamlTokenType.UNKNOWN
314
+ return self.tokens[0].type()
315
+
316
+
317
+ def create_grouped_tokens(tokens: YamlTokens) -> YamlErrorOr[ta.List[YamlParseToken]]:
318
+ tks = new_tokens(tokens)
319
+
320
+ tks = create_line_comment_token_groups(tks)
321
+
322
+ tks_ = create_literal_and_folded_token_groups(tks)
323
+ if isinstance(tks_, YamlError):
324
+ return tks_
325
+ tks = tks_
326
+
327
+ tks_ = create_anchor_and_alias_token_groups(tks)
328
+ if isinstance(tks_, YamlError):
329
+ return tks_
330
+ tks = tks_
331
+
332
+ tks_ = create_scalar_tag_token_groups(tks)
333
+ if isinstance(tks_, YamlError):
334
+ return tks_
335
+ tks = tks_
336
+
337
+ tks_ = create_anchor_with_scalar_tag_token_groups(tks)
338
+ if isinstance(tks_, YamlError):
339
+ return tks_
340
+ tks = tks_
341
+
342
+ tks_ = create_map_key_token_groups(tks)
343
+ if isinstance(tks_, YamlError):
344
+ return tks_
345
+ tks = tks_
346
+
347
+ tks = create_map_key_value_token_groups(tks)
348
+
349
+ tks_ = create_directive_token_groups(tks)
350
+ if isinstance(tks_, YamlError):
351
+ return tks_
352
+ tks = tks_
353
+
354
+ tks_ = create_document_tokens(tks)
355
+ if isinstance(tks_, YamlError):
356
+ return tks_
357
+ tks = tks_
358
+
359
+ return tks
360
+
361
+
362
+ def new_tokens(tks: YamlTokens) -> ta.List[YamlParseToken]:
363
+ ret: ta.List[YamlParseToken] = []
364
+ for tk in tks:
365
+ ret.append(YamlParseToken(token=tk))
366
+ return ret
367
+
368
+
369
+ def create_line_comment_token_groups(tokens: ta.List[YamlParseToken]) -> ta.List[YamlParseToken]:
370
+ ret: ta.List[YamlParseToken] = []
371
+ for i in range(len(tokens)):
372
+ tk = tokens[i]
373
+ if tk.type() == YamlTokenType.COMMENT:
374
+ if i > 0 and tokens[i - 1].line() == tk.line():
375
+ tokens[i - 1].line_comment = tk.raw_token()
376
+ else:
377
+ ret.append(tk)
378
+ else:
379
+ ret.append(tk)
380
+ return ret
381
+
382
+
383
+ def create_literal_and_folded_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
384
+ ret: ta.List[YamlParseToken] = []
385
+ i = -1
386
+ while True:
387
+ i += 1
388
+ if not (i < len(tokens)):
389
+ break
390
+ tk = tokens[i]
391
+ if tk.type() == YamlTokenType.LITERAL:
392
+ tks: ta.List[YamlParseToken] = [tk]
393
+ if i + 1 < len(tokens):
394
+ tks.append(tokens[i + 1])
395
+ ret.append(YamlParseToken(
396
+ group=YamlParseTokenGroup(
397
+ type=YamlParseTokenGroupType.LITERAL,
398
+ tokens=tks,
399
+ ),
400
+ ))
401
+ i += 1
402
+ elif tk.type() == YamlTokenType.FOLDED:
403
+ tks = [tk]
404
+ if i + 1 < len(tokens):
405
+ tks.append(tokens[i + 1])
406
+ ret.append(YamlParseToken(
407
+ group=YamlParseTokenGroup(
408
+ type=YamlParseTokenGroupType.FOLDED,
409
+ tokens=tks,
410
+ ),
411
+ ))
412
+ i += 1
413
+ else:
414
+ ret.append(tk)
415
+ return ret
416
+
417
+
418
+ def err_syntax(msg: str, tk: ta.Optional[YamlToken]) -> YamlError:
419
+ return yaml_error(f'Syntax error: {msg}, {tk}')
420
+
421
+
422
+ def create_anchor_and_alias_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
423
+ ret: ta.List[YamlParseToken] = []
424
+ i = -1
425
+ while True:
426
+ i += 1
427
+ if not (i < len(tokens)):
428
+ break
429
+ tk = tokens[i]
430
+ if tk.type() == YamlTokenType.ANCHOR:
431
+ if i + 1 >= len(tokens):
432
+ return err_syntax('undefined anchor name', tk.raw_token())
433
+ if i + 2 >= len(tokens):
434
+ return err_syntax('undefined anchor value', tk.raw_token())
435
+ anchor_name = YamlParseToken(
436
+ group=YamlParseTokenGroup(
437
+ type=YamlParseTokenGroupType.ANCHOR_NAME,
438
+ tokens=[tk, tokens[i + 1]],
439
+ ),
440
+ )
441
+ value_tk = tokens[i + 2]
442
+ if tk.line() == value_tk.line() and value_tk.type() == YamlTokenType.SEQUENCE_ENTRY:
443
+ return err_syntax(
444
+ 'sequence entries are not allowed after anchor on the same line',
445
+ value_tk.raw_token(),
446
+ )
447
+ if tk.line() == value_tk.line() and is_scalar_type(value_tk):
448
+ ret.append(YamlParseToken(
449
+ group=YamlParseTokenGroup(
450
+ type=YamlParseTokenGroupType.ANCHOR,
451
+ tokens=[anchor_name, value_tk],
452
+ ),
453
+ ))
454
+ i += 1
455
+ else:
456
+ ret.append(anchor_name)
457
+ i += 1
458
+ elif tk.type() == YamlTokenType.ALIAS:
459
+ if i + 1 == len(tokens):
460
+ return err_syntax('undefined alias name', tk.raw_token())
461
+ ret.append(YamlParseToken(
462
+ group=YamlParseTokenGroup(
463
+ type=YamlParseTokenGroupType.ALIAS,
464
+ tokens=[tk, tokens[i + 1]],
465
+ ),
466
+ ))
467
+ i += 1
468
+ else:
469
+ ret.append(tk)
470
+ return ret
471
+
472
+
473
+ def create_scalar_tag_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
474
+ ret: ta.List[YamlParseToken] = []
475
+ i = -1
476
+ while True:
477
+ i += 1
478
+ if not (i < len(tokens)):
479
+ break
480
+ tk = tokens[i]
481
+ if tk.type() != YamlTokenType.TAG:
482
+ ret.append(tk)
483
+ continue
484
+ tag = check.not_none(tk.raw_token())
485
+ if tag.value.startswith('!!'):
486
+ # secondary tag.
487
+ if tag.value in (
488
+ YamlReservedTagKeywords.INTEGER,
489
+ YamlReservedTagKeywords.FLOAT,
490
+ YamlReservedTagKeywords.STRING,
491
+ YamlReservedTagKeywords.BINARY,
492
+ YamlReservedTagKeywords.TIMESTAMP,
493
+ YamlReservedTagKeywords.BOOLEAN,
494
+ YamlReservedTagKeywords.NULL,
495
+ ):
496
+ if len(tokens) <= i + 1:
497
+ ret.append(tk)
498
+ continue
499
+ if tk.line() != tokens[i + 1].line():
500
+ ret.append(tk)
501
+ continue
502
+ if tokens[i + 1].group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
503
+ ret.append(tk)
504
+ continue
505
+ if is_scalar_type(tokens[i + 1]):
506
+ ret.append(YamlParseToken(
507
+ group=YamlParseTokenGroup(
508
+ type=YamlParseTokenGroupType.SCALAR_TAG,
509
+ tokens=[tk, tokens[i + 1]],
510
+ ),
511
+ ))
512
+ i += 1
513
+ else:
514
+ ret.append(tk)
515
+ elif tag.value == YamlReservedTagKeywords.MERGE:
516
+ if len(tokens) <= i + 1:
517
+ ret.append(tk)
518
+ continue
519
+ if tk.line() != tokens[i + 1].line():
520
+ ret.append(tk)
521
+ continue
522
+ if tokens[i + 1].group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
523
+ ret.append(tk)
524
+ continue
525
+ if tokens[i + 1].type() != YamlTokenType.MERGE_KEY:
526
+ return err_syntax('could not find merge key', tokens[i + 1].raw_token())
527
+ ret.append(YamlParseToken(
528
+ group=YamlParseTokenGroup(
529
+ type=YamlParseTokenGroupType.SCALAR_TAG,
530
+ tokens=[tk, tokens[i + 1]],
531
+ ),
532
+ ))
533
+ i += 1
534
+ else:
535
+ ret.append(tk)
536
+ else:
537
+ if len(tokens) <= i + 1:
538
+ ret.append(tk)
539
+ continue
540
+ if tk.line() != tokens[i + 1].line():
541
+ ret.append(tk)
542
+ continue
543
+ if tokens[i + 1].group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
544
+ ret.append(tk)
545
+ continue
546
+ if is_flow_type(tokens[i + 1]):
547
+ ret.append(tk)
548
+ continue
549
+ ret.append(YamlParseToken(
550
+ group=YamlParseTokenGroup(
551
+ type=YamlParseTokenGroupType.SCALAR_TAG,
552
+ tokens=[tk, tokens[i + 1]],
553
+ ),
554
+ ))
555
+ i += 1
556
+ return ret
557
+
558
+
559
+ def create_anchor_with_scalar_tag_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
560
+ ret: ta.List[YamlParseToken] = []
561
+ i = -1
562
+ while True:
563
+ i += 1
564
+ if not (i < len(tokens)):
565
+ break
566
+ tk = tokens[i]
567
+ if tk.group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
568
+ if i + 1 >= len(tokens):
569
+ return err_syntax('undefined anchor value', tk.raw_token())
570
+ value_tk = tokens[i + 1]
571
+ if tk.line() == value_tk.line() and value_tk.group_type() == YamlParseTokenGroupType.SCALAR_TAG:
572
+ ret.append(YamlParseToken(
573
+ group=YamlParseTokenGroup(
574
+ type=YamlParseTokenGroupType.ANCHOR,
575
+ tokens=[tk, tokens[i + 1]],
576
+ ),
577
+ ))
578
+ i += 1
579
+ else:
580
+ ret.append(tk)
581
+ else:
582
+ ret.append(tk)
583
+ return ret
584
+
585
+
586
+ def create_map_key_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
587
+ tks = create_map_key_by_mapping_key(tokens)
588
+ if isinstance(tks, YamlError):
589
+ return tks
590
+ return create_map_key_by_mapping_value(tks)
591
+
592
+
593
+ def create_map_key_by_mapping_key(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
594
+ ret: ta.List[YamlParseToken] = []
595
+ i = -1
596
+ while True:
597
+ i += 1
598
+ if not (i < len(tokens)):
599
+ break
600
+ tk = tokens[i]
601
+ if tk.type() == YamlTokenType.MAPPING_KEY:
602
+ if i + 1 >= len(tokens):
603
+ return err_syntax('undefined map key', tk.raw_token())
604
+ ret.append(YamlParseToken(
605
+ group=YamlParseTokenGroup(
606
+ type=YamlParseTokenGroupType.MAP_KEY,
607
+ tokens=[tk, tokens[i + 1]],
608
+ ),
609
+ ))
610
+ i += 1
611
+ else:
612
+ ret.append(tk)
613
+ return ret
614
+
615
+
616
+ def create_map_key_by_mapping_value(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
617
+ ret: ta.List[YamlParseToken] = []
618
+ i = -1
619
+ while True:
620
+ i += 1
621
+ if not (i < len(tokens)):
622
+ break
623
+ tk = tokens[i]
624
+ if tk.type() == YamlTokenType.MAPPING_VALUE:
625
+ if i == 0:
626
+ return err_syntax('unexpected key name', tk.raw_token())
627
+ map_key_tk = tokens[i - 1]
628
+ if is_not_map_key_type(map_key_tk):
629
+ return err_syntax('found an invalid key for this map', tokens[i].raw_token())
630
+ new_tk = YamlParseToken(
631
+ token=map_key_tk.token,
632
+ group=map_key_tk.group,
633
+ )
634
+ map_key_tk.token = None
635
+ map_key_tk.group = YamlParseTokenGroup(
636
+ type=YamlParseTokenGroupType.MAP_KEY,
637
+ tokens=[new_tk, tk],
638
+ )
639
+ else:
640
+ ret.append(tk)
641
+ return ret
642
+
643
+
644
+ def create_map_key_value_token_groups(tokens: ta.List[YamlParseToken]) -> ta.List[YamlParseToken]:
645
+ ret: ta.List[YamlParseToken] = []
646
+ i = -1
647
+ while True:
648
+ i += 1
649
+ if not (i < len(tokens)):
650
+ break
651
+ tk = tokens[i]
652
+ if tk.group_type() == YamlParseTokenGroupType.MAP_KEY:
653
+ if len(tokens) <= i + 1:
654
+ ret.append(tk)
655
+ continue
656
+ value_tk = tokens[i + 1]
657
+ if tk.line() != value_tk.line():
658
+ ret.append(tk)
659
+ continue
660
+ if value_tk.group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
661
+ ret.append(tk)
662
+ continue
663
+ if (
664
+ value_tk.type() == YamlTokenType.TAG and
665
+ value_tk.group_type() != YamlParseTokenGroupType.SCALAR_TAG
666
+ ):
667
+ ret.append(tk)
668
+ continue
669
+
670
+ if is_scalar_type(value_tk) or value_tk.type() == YamlTokenType.TAG:
671
+ ret.append(YamlParseToken(
672
+ group=YamlParseTokenGroup(
673
+ type=YamlParseTokenGroupType.MAP_KEY_VALUE,
674
+ tokens=[tk, value_tk],
675
+ ),
676
+ ))
677
+ i += 1
678
+ else:
679
+ ret.append(tk)
680
+ continue
681
+ else:
682
+ ret.append(tk)
683
+ return ret
684
+
685
+
686
+ def create_directive_token_groups(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
687
+ ret: ta.List[YamlParseToken] = []
688
+ i = -1
689
+ while True:
690
+ i += 1
691
+ if not (i < len(tokens)):
692
+ break
693
+ tk = tokens[i]
694
+ if tk.type() == YamlTokenType.DIRECTIVE:
695
+ if i + 1 >= len(tokens):
696
+ return err_syntax('undefined directive value', tk.raw_token())
697
+ directive_name = YamlParseToken(
698
+ group=YamlParseTokenGroup(
699
+ type=YamlParseTokenGroupType.DIRECTIVE_NAME,
700
+ tokens=[tk, tokens[i + 1]],
701
+ ),
702
+ )
703
+ i += 1
704
+ value_tks: ta.List[YamlParseToken] = []
705
+ for j in range(i + 1, len(tokens)):
706
+ if tokens[j].line() != tk.line():
707
+ break
708
+ value_tks.append(tokens[j])
709
+ i += 1
710
+ if i + 1 >= len(tokens) or tokens[i + 1].type() != YamlTokenType.DOCUMENT_HEADER:
711
+ return err_syntax('unexpected directive value. document not started', tk.raw_token())
712
+ if len(value_tks) != 0:
713
+ ret.append(YamlParseToken(
714
+ group=YamlParseTokenGroup(
715
+ type=YamlParseTokenGroupType.DIRECTIVE,
716
+ tokens=[directive_name, *value_tks],
717
+ ),
718
+ ))
719
+ else:
720
+ ret.append(directive_name)
721
+ else:
722
+ ret.append(tk)
723
+ return ret
724
+
725
+
726
+ def create_document_tokens(tokens: ta.List[YamlParseToken]) -> YamlErrorOr[ta.List[YamlParseToken]]:
727
+ ret: ta.List[YamlParseToken] = []
728
+ i = -1
729
+ while True:
730
+ i += 1
731
+ if not (i < len(tokens)):
732
+ break
733
+ tk = tokens[i]
734
+ if tk.type() == YamlTokenType.DOCUMENT_HEADER:
735
+ if i != 0:
736
+ ret.append(YamlParseToken(
737
+ group=YamlParseTokenGroup(tokens=tokens[:i]),
738
+ ))
739
+ if i + 1 == len(tokens):
740
+ # if current token is last token, add DocumentHeader only tokens to ret.
741
+ ret.append(YamlParseToken(
742
+ group=YamlParseTokenGroup(
743
+ type=YamlParseTokenGroupType.DOCUMENT,
744
+ tokens=[tk],
745
+ ),
746
+ ))
747
+ return ret
748
+ if tokens[i + 1].type() == YamlTokenType.DOCUMENT_HEADER:
749
+ ret.append(YamlParseToken(
750
+ group=YamlParseTokenGroup(
751
+ type=YamlParseTokenGroupType.DOCUMENT,
752
+ tokens=[tk],
753
+ ),
754
+ ))
755
+ return ret
756
+ if tokens[i].line() == tokens[i + 1].line():
757
+ if tokens[i + 1].group_type() in (
758
+ YamlParseTokenGroupType.MAP_KEY,
759
+ YamlParseTokenGroupType.MAP_KEY_VALUE,
760
+ ):
761
+ return err_syntax(
762
+ 'value cannot be placed after document separator',
763
+ tokens[i + 1].raw_token(),
764
+ )
765
+ if tokens[i + 1].type() == YamlTokenType.SEQUENCE_ENTRY:
766
+ return err_syntax(
767
+ 'value cannot be placed after document separator',
768
+ tokens[i + 1].raw_token(),
769
+ )
770
+ tks = create_document_tokens(tokens[i + 1:])
771
+ if isinstance(tks, YamlError):
772
+ return tks
773
+ if len(tks) != 0:
774
+ tks[0].set_group_type(YamlParseTokenGroupType.DOCUMENT)
775
+ check.not_none(tks[0].group).tokens = list(check.not_none(tks[0].group).tokens)
776
+ ret.extend(tks)
777
+ return ret
778
+ ret.append(YamlParseToken(
779
+ group=YamlParseTokenGroup(
780
+ type=YamlParseTokenGroupType.DOCUMENT,
781
+ tokens=[tk],
782
+ ),
783
+ ))
784
+ return ret
785
+ elif tk.type() == YamlTokenType.DOCUMENT_END:
786
+ if i != 0:
787
+ ret.append(YamlParseToken(
788
+ group=YamlParseTokenGroup(
789
+ type=YamlParseTokenGroupType.DOCUMENT,
790
+ tokens=tokens[0: i + 1],
791
+ ),
792
+ ))
793
+ if i + 1 == len(tokens):
794
+ return ret
795
+ if is_scalar_type(tokens[i + 1]):
796
+ return err_syntax('unexpected end content', tokens[i + 1].raw_token())
797
+
798
+ tks = create_document_tokens(tokens[i + 1:])
799
+ if isinstance(tks, YamlError):
800
+ return tks
801
+ ret.extend(tks)
802
+ return ret
803
+ ret.append(YamlParseToken(
804
+ group=YamlParseTokenGroup(
805
+ type=YamlParseTokenGroupType.DOCUMENT,
806
+ tokens=tokens,
807
+ ),
808
+ ))
809
+ return ret
810
+
811
+
812
+ def is_scalar_type(tk: YamlParseToken) -> bool:
813
+ if tk.group_type() in (YamlParseTokenGroupType.MAP_KEY, YamlParseTokenGroupType.MAP_KEY_VALUE):
814
+ return False
815
+ typ = tk.type()
816
+ return typ in (
817
+ YamlTokenType.ANCHOR,
818
+ YamlTokenType.ALIAS,
819
+ YamlTokenType.LITERAL,
820
+ YamlTokenType.FOLDED,
821
+ YamlTokenType.NULL,
822
+ YamlTokenType.IMPLICIT_NULL,
823
+ YamlTokenType.BOOL,
824
+ YamlTokenType.INTEGER,
825
+ YamlTokenType.BINARY_INTEGER,
826
+ YamlTokenType.OCTET_INTEGER,
827
+ YamlTokenType.HEX_INTEGER,
828
+ YamlTokenType.FLOAT,
829
+ YamlTokenType.INFINITY,
830
+ YamlTokenType.NAN,
831
+ YamlTokenType.STRING,
832
+ YamlTokenType.SINGLE_QUOTE,
833
+ YamlTokenType.DOUBLE_QUOTE,
834
+ )
835
+
836
+
837
+ def is_not_map_key_type(tk: YamlParseToken) -> bool:
838
+ typ = tk.type()
839
+ return typ in (
840
+ YamlTokenType.DIRECTIVE,
841
+ YamlTokenType.DOCUMENT_HEADER,
842
+ YamlTokenType.DOCUMENT_END,
843
+ YamlTokenType.COLLECT_ENTRY,
844
+ YamlTokenType.MAPPING_START,
845
+ YamlTokenType.MAPPING_VALUE,
846
+ YamlTokenType.MAPPING_END,
847
+ YamlTokenType.SEQUENCE_START,
848
+ YamlTokenType.SEQUENCE_ENTRY,
849
+ YamlTokenType.SEQUENCE_END,
850
+ )
851
+
852
+
853
+ def is_flow_type(tk: YamlParseToken) -> bool:
854
+ typ = tk.type()
855
+ return typ in (
856
+ YamlTokenType.MAPPING_START,
857
+ YamlTokenType.MAPPING_END,
858
+ YamlTokenType.SEQUENCE_START,
859
+ YamlTokenType.SEQUENCE_ENTRY,
860
+ )
861
+
862
+
863
+ ##
864
+
865
+
866
+ class YamlNodeMakers:
867
+ def __new__(cls, *args, **kwargs): # noqa
868
+ raise TypeError
869
+
870
+ @staticmethod
871
+ def new_mapping_node(
872
+ ctx: YamlParsingContext,
873
+ tk: YamlParseToken,
874
+ is_flow: bool,
875
+ *values: ast.MappingValueYamlNode,
876
+ ) -> YamlErrorOr[ast.MappingYamlNode]:
877
+ node = ast.mapping(check.not_none(tk.raw_token()), is_flow, *values)
878
+ node.set_path(ctx.path)
879
+ return node
880
+
881
+ @staticmethod
882
+ def new_mapping_value_node(
883
+ ctx: YamlParsingContext,
884
+ colon_tk: YamlParseToken,
885
+ entry_tk: ta.Optional[YamlParseToken],
886
+ key: ast.MapKeyYamlNode,
887
+ value: ast.YamlNode,
888
+ ) -> YamlErrorOr[ast.MappingValueYamlNode]:
889
+ node = ast.mapping_value(check.not_none(colon_tk.raw_token()), key, value)
890
+ node.set_path(ctx.path)
891
+ node.collect_entry = YamlParseToken.raw_token(entry_tk)
892
+ if check.not_none(key.get_token()).position.line == check.not_none(value.get_token()).position.line:
893
+ # originally key was commented, but now that null value has been added, value must be commented.
894
+ if (err := set_line_comment(ctx, value, colon_tk)) is not None:
895
+ return err
896
+ # set line comment by colon_tk or entry_tk.
897
+ if (err := set_line_comment(ctx, value, entry_tk)) is not None:
898
+ return err
899
+ else:
900
+ if (err := set_line_comment(ctx, key, colon_tk)) is not None:
901
+ return err
902
+ # set line comment by colon_tk or entry_tk.
903
+ if (err := set_line_comment(ctx, key, entry_tk)) is not None:
904
+ return err
905
+ return node
906
+
907
+ @staticmethod
908
+ def new_mapping_key_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.MappingKeyYamlNode]: # noqa
909
+ node = ast.mapping_key(check.not_none(YamlParseToken.raw_token(tk)))
910
+ node.set_path(ctx.path)
911
+ if (err := set_line_comment(ctx, node, tk)) is not None:
912
+ return err
913
+ return node
914
+
915
+ @staticmethod
916
+ def new_anchor_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.AnchorYamlNode]:
917
+ node = ast.anchor(check.not_none(YamlParseToken.raw_token(tk)))
918
+ node.set_path(ctx.path)
919
+ if (err := set_line_comment(ctx, node, tk)) is not None:
920
+ return err
921
+ return node
922
+
923
+ @staticmethod
924
+ def new_alias_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.AliasYamlNode]:
925
+ node = ast.alias(check.not_none(YamlParseToken.raw_token(tk)))
926
+ node.set_path(ctx.path)
927
+ if (err := set_line_comment(ctx, node, tk)) is not None:
928
+ return err
929
+ return node
930
+
931
+ @staticmethod
932
+ def new_directive_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.DirectiveYamlNode]: # noqa
933
+ node = ast.directive(check.not_none(YamlParseToken.raw_token(tk)))
934
+ node.set_path(ctx.path)
935
+ if (err := set_line_comment(ctx, node, tk)) is not None:
936
+ return err
937
+ return node
938
+
939
+ @staticmethod
940
+ def new_merge_key_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.MergeKeyYamlNode]: # noqa
941
+ node = ast.merge_key(check.not_none(YamlParseToken.raw_token(tk)))
942
+ node.set_path(ctx.path)
943
+ if (err := set_line_comment(ctx, node, tk)) is not None:
944
+ return err
945
+ return node
946
+
947
+ @staticmethod
948
+ def new_null_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.NullYamlNode]:
949
+ node = ast.null(check.not_none(YamlParseToken.raw_token(tk)))
950
+ node.set_path(ctx.path)
951
+ if (err := set_line_comment(ctx, node, tk)) is not None:
952
+ return err
953
+ return node
954
+
955
+ @staticmethod
956
+ def new_bool_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.BoolYamlNode]:
957
+ node = ast.bool_(check.not_none(YamlParseToken.raw_token(tk)))
958
+ node.set_path(ctx.path)
959
+ if (err := set_line_comment(ctx, node, tk)) is not None:
960
+ return err
961
+ return node
962
+
963
+ @staticmethod
964
+ def new_integer_node(ctx: YamlParsingContext, tk: YamlParseToken) -> YamlErrorOr[ast.IntegerYamlNode]:
965
+ node = ast.integer(check.not_none(YamlParseToken.raw_token(tk)))
966
+ node.set_path(ctx.path)
967
+ if (err := set_line_comment(ctx, node, tk)) is not None:
968
+ return err
969
+ return node
970
+
971
+ @staticmethod
972
+ def new_float_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.FloatYamlNode]:
973
+ node = ast.float_(check.not_none(YamlParseToken.raw_token(tk)))
974
+ node.set_path(ctx.path)
975
+ if (err := set_line_comment(ctx, node, tk)) is not None:
976
+ return err
977
+ return node
978
+
979
+ @staticmethod
980
+ def new_infinity_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.InfinityYamlNode]: # noqa
981
+ node = ast.infinity(check.not_none(YamlParseToken.raw_token(tk)))
982
+ node.set_path(ctx.path)
983
+ if (err := set_line_comment(ctx, node, tk)) is not None:
984
+ return err
985
+ return node
986
+
987
+ @staticmethod
988
+ def new_nan_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.NanYamlNode]:
989
+ node = ast.nan(check.not_none(YamlParseToken.raw_token(tk)))
990
+ node.set_path(ctx.path)
991
+ if (err := set_line_comment(ctx, node, tk)) is not None:
992
+ return err
993
+ return node
994
+
995
+ @staticmethod
996
+ def new_string_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.StringYamlNode]:
997
+ node = ast.string(check.not_none(YamlParseToken.raw_token(tk)))
998
+ node.set_path(ctx.path)
999
+ if (err := set_line_comment(ctx, node, tk)) is not None:
1000
+ return err
1001
+ return node
1002
+
1003
+ @staticmethod
1004
+ def new_literal_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.LiteralYamlNode]:
1005
+ node = ast.literal(check.not_none(YamlParseToken.raw_token(tk)))
1006
+ node.set_path(ctx.path)
1007
+ if (err := set_line_comment(ctx, node, tk)) is not None:
1008
+ return err
1009
+ return node
1010
+
1011
+ @staticmethod
1012
+ def new_tag_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.TagYamlNode]:
1013
+ node = ast.tag(check.not_none(YamlParseToken.raw_token(tk)))
1014
+ node.set_path(ctx.path)
1015
+ if (err := set_line_comment(ctx, node, tk)) is not None:
1016
+ return err
1017
+ return node
1018
+
1019
+ @staticmethod
1020
+ def new_sequence_node(ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken], is_flow: bool) -> YamlErrorOr[ast.SequenceYamlNode]: # noqa
1021
+ node = ast.sequence(check.not_none(YamlParseToken.raw_token(tk)), is_flow)
1022
+ node.set_path(ctx.path)
1023
+ if (err := set_line_comment(ctx, node, tk)) is not None:
1024
+ return err
1025
+ return node
1026
+
1027
+ @staticmethod
1028
+ def new_tag_default_scalar_value_node(ctx: YamlParsingContext, tag: YamlToken) -> YamlErrorOr[ast.ScalarYamlNode]:
1029
+ pos = copy.copy(tag.position)
1030
+ pos.column += 1
1031
+
1032
+ tk: YamlErrorOr[YamlParseToken]
1033
+ node: YamlErrorOr[ast.ScalarYamlNode]
1034
+
1035
+ if tag.value == YamlReservedTagKeywords.INTEGER:
1036
+ tk = YamlParseToken(token=new_yaml_token('0', '0', pos))
1037
+ n0 = YamlNodeMakers.new_integer_node(ctx, tk)
1038
+ if isinstance(n0, YamlError):
1039
+ return n0
1040
+ node = n0
1041
+ elif tag.value == YamlReservedTagKeywords.FLOAT:
1042
+ tk = YamlParseToken(token=new_yaml_token('0', '0', pos))
1043
+ n1 = YamlNodeMakers.new_float_node(ctx, tk)
1044
+ if isinstance(n1, YamlError):
1045
+ return n1
1046
+ node = n1
1047
+ elif tag.value in (
1048
+ YamlReservedTagKeywords.STRING,
1049
+ YamlReservedTagKeywords.BINARY,
1050
+ YamlReservedTagKeywords.TIMESTAMP,
1051
+ ):
1052
+ tk = YamlParseToken(token=new_yaml_token('', '', pos))
1053
+ n2 = YamlNodeMakers.new_string_node(ctx, tk)
1054
+ if isinstance(n2, YamlError):
1055
+ return n2
1056
+ node = n2
1057
+ elif tag.value == YamlReservedTagKeywords.BOOLEAN:
1058
+ tk = YamlParseToken(token=new_yaml_token('false', 'false', pos))
1059
+ n3 = YamlNodeMakers.new_bool_node(ctx, tk)
1060
+ if isinstance(n3, YamlError):
1061
+ return n3
1062
+ node = n3
1063
+ elif tag.value == YamlReservedTagKeywords.NULL:
1064
+ tk = YamlParseToken(token=new_yaml_token('null', 'null', pos))
1065
+ n4 = YamlNodeMakers.new_null_node(ctx, tk)
1066
+ if isinstance(n4, YamlError):
1067
+ return n4
1068
+ node = n4
1069
+ else:
1070
+ return err_syntax(f'cannot assign default value for {tag.value!r} tag', tag)
1071
+ ctx.insert_token(tk)
1072
+ ctx.go_next()
1073
+ return node
1074
+
1075
+
1076
+ def set_line_comment(ctx: YamlParsingContext, node: ast.YamlNode, tk: ta.Optional[YamlParseToken]) -> ta.Optional[YamlError]: # noqa
1077
+ if tk is None or tk.line_comment is None:
1078
+ return None
1079
+ comment = ast.comment_group([tk.line_comment])
1080
+ comment.set_path(ctx.path)
1081
+ if (err := node.set_comment(comment)) is not None:
1082
+ return err
1083
+ return None
1084
+
1085
+
1086
+ def set_head_comment(cm: ta.Optional[ast.CommentGroupYamlNode], value: ast.YamlNode) -> ta.Optional[YamlError]:
1087
+ if cm is None:
1088
+ return None
1089
+ n = value
1090
+ if isinstance(n, ast.MappingYamlNode):
1091
+ if len(n.values) != 0 and value.get_comment() is None:
1092
+ cm.set_path(n.values[0].get_path())
1093
+ return n.values[0].set_comment(cm)
1094
+ elif isinstance(n, ast.MappingValueYamlNode):
1095
+ cm.set_path(n.get_path())
1096
+ return n.set_comment(cm)
1097
+ cm.set_path(value.get_path())
1098
+ return value.set_comment(cm)
1099
+
1100
+
1101
+ ##
1102
+
1103
+
1104
+ ParseMode = int # ta.TypeAlias # omlish-amalg-typing-no-move
1105
+
1106
+ PARSE_COMMENTS = ParseMode(1) # parse comments and add them to AST
1107
+
1108
+
1109
+ # ParseBytes parse from byte slice, and returns ast.File
1110
+ def parse_str(
1111
+ s: str,
1112
+ mode: ParseMode = ParseMode(0),
1113
+ *opts: Option,
1114
+ ) -> YamlErrorOr[ast.YamlFile]:
1115
+ tokens = yaml_tokenize(s)
1116
+ f = parse(tokens, mode, *opts)
1117
+ if isinstance(f, YamlError):
1118
+ return f
1119
+ return f
1120
+
1121
+
1122
+ # Parse parse from token instances, and returns ast.File
1123
+ def parse(
1124
+ tokens: YamlTokens,
1125
+ mode: ParseMode = ParseMode(0),
1126
+ *opts: Option,
1127
+ ) -> YamlErrorOr[ast.YamlFile]:
1128
+ if (tk := tokens.invalid_token()) is not None:
1129
+ return err_syntax(check.not_none(tk.error).message, tk)
1130
+ p = YamlParser.new_parser(tokens, mode, opts)
1131
+ if isinstance(p, YamlError):
1132
+ return p
1133
+ f = p.parse(YamlParsingContext.new())
1134
+ if isinstance(f, YamlError):
1135
+ return f
1136
+ return f
1137
+
1138
+
1139
+ #
1140
+
1141
+
1142
+ YAMLVersion = str # ta.TypeAlias # omlish-amalg-typing-no-move
1143
+
1144
+ YAML10 = YAMLVersion('1.0')
1145
+ YAML11 = YAMLVersion('1.1')
1146
+ YAML12 = YAMLVersion('1.2')
1147
+ YAML13 = YAMLVersion('1.3')
1148
+
1149
+ YAML_VERSION_MAP: ta.Mapping[str, YAMLVersion] = {
1150
+ '1.0': YAML10,
1151
+ '1.1': YAML11,
1152
+ '1.2': YAML12,
1153
+ '1.3': YAML13,
1154
+ }
1155
+
1156
+
1157
+ #
1158
+
1159
+ @dc.dataclass()
1160
+ class YamlParser:
1161
+ tokens: ta.List[YamlParseToken]
1162
+ path_map: ta.Dict[str, ast.YamlNode]
1163
+ yaml_version: YAMLVersion = YAMLVersion('')
1164
+ allow_duplicate_map_key: bool = False
1165
+ secondary_tag_directive: ta.Optional[ast.DirectiveYamlNode] = None
1166
+
1167
+ @staticmethod
1168
+ def new_parser(
1169
+ tokens: YamlTokens,
1170
+ mode: ParseMode,
1171
+ opts: ta.Iterable[Option],
1172
+ ) -> YamlErrorOr['YamlParser']:
1173
+ filtered_tokens: ta.List[YamlToken] = []
1174
+ if mode & PARSE_COMMENTS != 0:
1175
+ filtered_tokens = tokens
1176
+ else:
1177
+ for tk in tokens:
1178
+ if tk.type == YamlTokenType.COMMENT:
1179
+ continue
1180
+ # keep prev/next reference between tokens containing comments
1181
+ # https://github.com/goccy/go-yaml/issues/254
1182
+ filtered_tokens.append(tk)
1183
+ tks = create_grouped_tokens(YamlTokens(filtered_tokens))
1184
+ if isinstance(tks, YamlError):
1185
+ return tks
1186
+ p = YamlParser(
1187
+ tokens=tks,
1188
+ path_map={},
1189
+ )
1190
+ for opt in opts:
1191
+ opt(p)
1192
+ return p
1193
+
1194
+ def parse(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.YamlFile]:
1195
+ file = ast.YamlFile(docs=[])
1196
+ for token in self.tokens:
1197
+ doc = self.parse_document(ctx, check.not_none(token.group))
1198
+ if isinstance(doc, YamlError):
1199
+ return doc
1200
+ file.docs.append(doc)
1201
+ return file
1202
+
1203
+ def parse_document(
1204
+ self,
1205
+ ctx: YamlParsingContext,
1206
+ doc_group: YamlParseTokenGroup,
1207
+ ) -> YamlErrorOr[ast.DocumentYamlNode]:
1208
+ if len(doc_group.tokens) == 0:
1209
+ return ast.document(doc_group.raw_token(), None)
1210
+
1211
+ self.path_map: ta.Dict[str, ast.YamlNode] = {}
1212
+
1213
+ tokens = doc_group.tokens
1214
+ start: ta.Optional[YamlToken] = None
1215
+ end: ta.Optional[YamlToken] = None
1216
+ if YamlParseToken.type(doc_group.first()) == YamlTokenType.DOCUMENT_HEADER:
1217
+ start = YamlParseToken.raw_token(doc_group.first())
1218
+ tokens = tokens[1:]
1219
+
1220
+ clear_yaml_version = False
1221
+ try:
1222
+ if YamlParseToken.type(doc_group.last()) == YamlTokenType.DOCUMENT_END:
1223
+ end = YamlParseToken.raw_token(doc_group.last())
1224
+ tokens = tokens[:len(tokens) - 1]
1225
+ # clear yaml version value if DocumentEnd token (...) is specified.
1226
+ clear_yaml_version = True
1227
+
1228
+ if len(tokens) == 0:
1229
+ return ast.document(doc_group.raw_token(), None)
1230
+
1231
+ body = self.parse_document_body(ctx.with_group(YamlParseTokenGroup(
1232
+ type=YamlParseTokenGroupType.DOCUMENT_BODY,
1233
+ tokens=tokens,
1234
+ )))
1235
+ if isinstance(body, YamlError):
1236
+ return body
1237
+ node = ast.document(start, body)
1238
+ node.end = end
1239
+ return node
1240
+
1241
+ finally:
1242
+ if clear_yaml_version:
1243
+ self.yaml_version = ''
1244
+
1245
+ def parse_document_body(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.YamlNode]:
1246
+ node = self.parse_token(ctx, ctx.current_token())
1247
+ if isinstance(node, YamlError):
1248
+ return node
1249
+ if ctx.next():
1250
+ return err_syntax('value is not allowed in this context', YamlParseToken.raw_token(ctx.current_token()))
1251
+ return node
1252
+
1253
+ def parse_token(self, ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ast.YamlNode]:
1254
+ if YamlParseToken.group_type(tk) in (
1255
+ YamlParseTokenGroupType.MAP_KEY,
1256
+ YamlParseTokenGroupType.MAP_KEY_VALUE,
1257
+ ):
1258
+ return self.parse_map(ctx)
1259
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.DIRECTIVE:
1260
+ node0 = self.parse_directive(
1261
+ ctx.with_group(check.not_none(check.not_none(tk).group)),
1262
+ check.not_none(check.not_none(tk).group),
1263
+ )
1264
+ if isinstance(node0, YamlError):
1265
+ return node0
1266
+ ctx.go_next()
1267
+ return node0
1268
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.DIRECTIVE_NAME:
1269
+ node1 = self.parse_directive_name(ctx.with_group(check.not_none(check.not_none(tk).group)))
1270
+ if isinstance(node1, YamlError):
1271
+ return node1
1272
+ ctx.go_next()
1273
+ return node1
1274
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR:
1275
+ node2 = self.parse_anchor(
1276
+ ctx.with_group(check.not_none(check.not_none(tk).group)),
1277
+ check.not_none(check.not_none(tk).group),
1278
+ )
1279
+ if isinstance(node2, YamlError):
1280
+ return node2
1281
+ ctx.go_next()
1282
+ return node2
1283
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME:
1284
+ anchor = self.parse_anchor_name(ctx.with_group(check.not_none(check.not_none(tk).group)))
1285
+ if isinstance(anchor, YamlError):
1286
+ return anchor
1287
+ ctx.go_next()
1288
+ if ctx.is_token_not_found():
1289
+ return err_syntax('could not find anchor value', YamlParseToken.raw_token(tk))
1290
+ value = self.parse_token(ctx, ctx.current_token())
1291
+ if isinstance(value, YamlError):
1292
+ return value
1293
+ if isinstance(value, ast.AnchorYamlNode):
1294
+ return err_syntax('anchors cannot be used consecutively', value.get_token())
1295
+ anchor.value = value
1296
+ return anchor
1297
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ALIAS:
1298
+ node3 = self.parse_alias(ctx.with_group(check.not_none(check.not_none(tk).group)))
1299
+ if isinstance(node3, YamlError):
1300
+ return node3
1301
+ ctx.go_next()
1302
+ return node3
1303
+ elif YamlParseToken.group_type(tk) in (
1304
+ YamlParseTokenGroupType.LITERAL,
1305
+ YamlParseTokenGroupType.FOLDED,
1306
+ ):
1307
+ node4 = self.parse_literal(ctx.with_group(check.not_none(check.not_none(tk).group)))
1308
+ if isinstance(node4, YamlError):
1309
+ return node4
1310
+ ctx.go_next()
1311
+ return node4
1312
+ elif YamlParseToken.group_type(tk) == YamlParseTokenGroupType.SCALAR_TAG:
1313
+ node5 = self.parse_tag(ctx.with_group(check.not_none(check.not_none(tk).group)))
1314
+ if isinstance(node5, YamlError):
1315
+ return node5
1316
+ ctx.go_next()
1317
+ return node5
1318
+ if YamlParseToken.type(tk) == YamlTokenType.COMMENT:
1319
+ return ta.cast('YamlErrorOr[ast.YamlNode]', check.not_none(self.parse_comment(ctx)))
1320
+ elif YamlParseToken.type(tk) == YamlTokenType.TAG:
1321
+ return self.parse_tag(ctx)
1322
+ elif YamlParseToken.type(tk) == YamlTokenType.MAPPING_START:
1323
+ return self.parse_flow_map(ctx.with_flow(True))
1324
+ elif YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_START:
1325
+ return self.parse_flow_sequence(ctx.with_flow(True))
1326
+ elif YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_ENTRY:
1327
+ return self.parse_sequence(ctx)
1328
+ elif YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_END:
1329
+ # SequenceEndType is always validated in parse_flow_sequence.
1330
+ # Therefore, if this is found in other cases, it is treated as a syntax error.
1331
+ return err_syntax("could not find '[' character corresponding to ']'", YamlParseToken.raw_token(tk))
1332
+ elif YamlParseToken.type(tk) == YamlTokenType.MAPPING_END:
1333
+ # MappingEndType is always validated in parse_flow_map.
1334
+ # Therefore, if this is found in other cases, it is treated as a syntax error.
1335
+ return err_syntax("could not find '{' character corresponding to '}'", YamlParseToken.raw_token(tk))
1336
+ elif YamlParseToken.type(tk) == YamlTokenType.MAPPING_VALUE:
1337
+ return err_syntax('found an invalid key for this map', YamlParseToken.raw_token(tk))
1338
+ node6 = self.parse_scalar_value(ctx, tk)
1339
+ if isinstance(node6, YamlError):
1340
+ return node6
1341
+ ctx.go_next()
1342
+ return check.not_none(node6)
1343
+
1344
+ def parse_scalar_value(self, ctx: YamlParsingContext, tk: ta.Optional[YamlParseToken]) -> YamlErrorOr[ta.Optional[ast.ScalarYamlNode]]: # noqa
1345
+ tk = check.not_none(tk)
1346
+ if tk.group is not None:
1347
+ if tk.group_type() == YamlParseTokenGroupType.ANCHOR:
1348
+ return self.parse_anchor(ctx.with_group(tk.group), tk.group)
1349
+ elif tk.group_type() == YamlParseTokenGroupType.ANCHOR_NAME:
1350
+ anchor = self.parse_anchor_name(ctx.with_group(tk.group))
1351
+ if isinstance(anchor, YamlError):
1352
+ return anchor
1353
+ ctx.go_next()
1354
+ if ctx.is_token_not_found():
1355
+ return err_syntax('could not find anchor value', tk.raw_token())
1356
+ value = self.parse_token(ctx, ctx.current_token())
1357
+ if isinstance(value, YamlError):
1358
+ return value
1359
+ if isinstance(value, ast.AnchorYamlNode):
1360
+ return err_syntax('anchors cannot be used consecutively', value.get_token())
1361
+ anchor.value = value
1362
+ return anchor
1363
+ elif tk.group_type() == YamlParseTokenGroupType.ALIAS:
1364
+ return self.parse_alias(ctx.with_group(tk.group))
1365
+ elif tk.group_type() in (
1366
+ YamlParseTokenGroupType.LITERAL,
1367
+ YamlParseTokenGroupType.FOLDED,
1368
+ ):
1369
+ return self.parse_literal(ctx.with_group(tk.group))
1370
+ elif tk.group_type() == YamlParseTokenGroupType.SCALAR_TAG:
1371
+ return self.parse_tag(ctx.with_group(tk.group))
1372
+ else:
1373
+ return err_syntax('unexpected scalar value', tk.raw_token())
1374
+ if tk.type() == YamlTokenType.MERGE_KEY:
1375
+ return YamlNodeMakers.new_merge_key_node(ctx, tk)
1376
+ if tk.type() in (YamlTokenType.NULL, YamlTokenType.IMPLICIT_NULL):
1377
+ return YamlNodeMakers.new_null_node(ctx, tk)
1378
+ if tk.type() == YamlTokenType.BOOL:
1379
+ return YamlNodeMakers.new_bool_node(ctx, tk)
1380
+ if tk.type() in (
1381
+ YamlTokenType.INTEGER,
1382
+ YamlTokenType.BINARY_INTEGER,
1383
+ YamlTokenType.OCTET_INTEGER,
1384
+ YamlTokenType.HEX_INTEGER,
1385
+ ):
1386
+ return YamlNodeMakers.new_integer_node(ctx, tk)
1387
+ if tk.type() == YamlTokenType.FLOAT:
1388
+ return YamlNodeMakers.new_float_node(ctx, tk)
1389
+ if tk.type() == YamlTokenType.INFINITY:
1390
+ return YamlNodeMakers.new_infinity_node(ctx, tk)
1391
+ if tk.type() == YamlTokenType.NAN:
1392
+ return YamlNodeMakers.new_nan_node(ctx, tk)
1393
+ if tk.type() in (
1394
+ YamlTokenType.STRING,
1395
+ YamlTokenType.SINGLE_QUOTE,
1396
+ YamlTokenType.DOUBLE_QUOTE,
1397
+ ):
1398
+ return YamlNodeMakers.new_string_node(ctx, tk)
1399
+ if tk.type() == YamlTokenType.TAG:
1400
+ # this case applies when it is a scalar tag and its value does not exist.
1401
+ # Examples of cases where the value does not exist include cases like `key: !!str,` or `!!str : value`.
1402
+ return self.parse_scalar_tag(ctx)
1403
+ return err_syntax('unexpected scalar value type', tk.raw_token())
1404
+
1405
+ def parse_flow_map(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.MappingYamlNode]:
1406
+ node = YamlNodeMakers.new_mapping_node(ctx, check.not_none(ctx.current_token()), True)
1407
+ if isinstance(node, YamlError):
1408
+ return node
1409
+ ctx.go_next() # skip MappingStart token
1410
+
1411
+ is_first = True
1412
+ while ctx.next():
1413
+ tk = ctx.current_token()
1414
+ if YamlParseToken.type(tk) == YamlTokenType.MAPPING_END:
1415
+ node.end = YamlParseToken.raw_token(tk)
1416
+ break
1417
+
1418
+ entry_tk: ta.Optional[YamlParseToken] = None
1419
+ if YamlParseToken.type(tk) == YamlTokenType.COLLECT_ENTRY:
1420
+ entry_tk = tk
1421
+ ctx.go_next()
1422
+ elif not is_first:
1423
+ return err_syntax("',' or '}' must be specified", YamlParseToken.raw_token(tk))
1424
+
1425
+ if YamlParseToken.type(tk := ctx.current_token()) == YamlTokenType.MAPPING_END:
1426
+ # this case is here: "{ elem, }".
1427
+ # In this case, ignore the last element and break mapping parsing.
1428
+ node.end = YamlParseToken.raw_token(tk)
1429
+ break
1430
+
1431
+ map_key_tk = ctx.current_token()
1432
+ if YamlParseToken.group_type(map_key_tk) == YamlParseTokenGroupType.MAP_KEY_VALUE:
1433
+ value0 = self.parse_map_key_value(
1434
+ ctx.with_group(check.not_none(check.not_none(map_key_tk).group)),
1435
+ check.not_none(check.not_none(map_key_tk).group),
1436
+ entry_tk,
1437
+ )
1438
+ if isinstance(value0, YamlError):
1439
+ return value0
1440
+ node.values.append(value0)
1441
+ ctx.go_next()
1442
+ elif YamlParseToken.group_type(map_key_tk) == YamlParseTokenGroupType.MAP_KEY:
1443
+ key0 = self.parse_map_key(
1444
+ ctx.with_group(check.not_none(check.not_none(map_key_tk).group)),
1445
+ check.not_none(check.not_none(map_key_tk).group),
1446
+ )
1447
+ if isinstance(key0, YamlError):
1448
+ return key0
1449
+ ctx = ctx.with_child(self.map_key_text(key0))
1450
+ colon_tk = check.not_none(check.not_none(map_key_tk).group).last()
1451
+ if self.is_flow_map_delim(check.not_none(ctx.next_token())):
1452
+ value1 = YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(check.not_none(colon_tk)))
1453
+ if isinstance(value1, YamlError):
1454
+ return value1
1455
+ map_value = YamlNodeMakers.new_mapping_value_node(
1456
+ ctx,
1457
+ check.not_none(colon_tk),
1458
+ entry_tk,
1459
+ key0,
1460
+ value1,
1461
+ )
1462
+ if isinstance(map_value, YamlError):
1463
+ return map_value
1464
+ node.values.append(map_value)
1465
+ ctx.go_next()
1466
+ else:
1467
+ ctx.go_next()
1468
+ if ctx.is_token_not_found():
1469
+ return err_syntax('could not find map value', YamlParseToken.raw_token(colon_tk))
1470
+ value2 = self.parse_token(ctx, ctx.current_token())
1471
+ if isinstance(value2, YamlError):
1472
+ return value2
1473
+ map_value = YamlNodeMakers.new_mapping_value_node(
1474
+ ctx,
1475
+ check.not_none(colon_tk),
1476
+ entry_tk,
1477
+ key0,
1478
+ value2,
1479
+ )
1480
+ if isinstance(map_value, YamlError):
1481
+ return map_value
1482
+ node.values.append(map_value)
1483
+ else:
1484
+ if not self.is_flow_map_delim(check.not_none(ctx.next_token())):
1485
+ err_tk = map_key_tk
1486
+ if err_tk is None:
1487
+ err_tk = tk
1488
+ return err_syntax('could not find flow map content', YamlParseToken.raw_token(err_tk))
1489
+ key1 = self.parse_scalar_value(ctx, map_key_tk)
1490
+ if isinstance(key1, YamlError):
1491
+ return key1
1492
+ value3 = YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(check.not_none(map_key_tk)))
1493
+ if isinstance(value3, YamlError):
1494
+ return value3
1495
+ map_value = YamlNodeMakers.new_mapping_value_node(
1496
+ ctx,
1497
+ check.not_none(map_key_tk),
1498
+ entry_tk,
1499
+ check.not_none(key1),
1500
+ value3,
1501
+ )
1502
+ if isinstance(map_value, YamlError):
1503
+ return map_value
1504
+ node.values.append(map_value)
1505
+ ctx.go_next()
1506
+ is_first = False
1507
+ if node.end is None:
1508
+ return err_syntax("could not find flow mapping end token '}'", node.start)
1509
+ ctx.go_next() # skip mapping end token.
1510
+ return node
1511
+
1512
+ def is_flow_map_delim(self, tk: YamlParseToken) -> bool:
1513
+ return tk.type() == YamlTokenType.MAPPING_END or tk.type() == YamlTokenType.COLLECT_ENTRY
1514
+
1515
+ def parse_map(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.MappingYamlNode]:
1516
+ key_tk = check.not_none(ctx.current_token())
1517
+ if key_tk.group is None:
1518
+ return err_syntax('unexpected map key', YamlParseToken.raw_token(key_tk))
1519
+ key_value_node: ast.MappingValueYamlNode
1520
+ if YamlParseToken.group_type(key_tk) == YamlParseTokenGroupType.MAP_KEY_VALUE:
1521
+ node0 = self.parse_map_key_value(
1522
+ ctx.with_group(check.not_none(key_tk.group)),
1523
+ check.not_none(key_tk.group),
1524
+ None,
1525
+ )
1526
+ if isinstance(node0, YamlError):
1527
+ return node0
1528
+ key_value_node = node0
1529
+ ctx.go_next()
1530
+ if (err := self.validate_map_key_value_next_token(ctx, key_tk, ctx.current_token())) is not None:
1531
+ return err
1532
+ else:
1533
+ key = self.parse_map_key(ctx.with_group(check.not_none(key_tk.group)), check.not_none(key_tk.group))
1534
+ if isinstance(key, YamlError):
1535
+ return key
1536
+ ctx.go_next()
1537
+
1538
+ value_tk = ctx.current_token()
1539
+ if (
1540
+ YamlParseToken.line(key_tk) == YamlParseToken.line(value_tk) and
1541
+ YamlParseToken.type(value_tk) == YamlTokenType.SEQUENCE_ENTRY
1542
+ ):
1543
+ return err_syntax(
1544
+ 'block sequence entries are not allowed in this context',
1545
+ YamlParseToken.raw_token(value_tk),
1546
+ )
1547
+ ctx = ctx.with_child(self.map_key_text(key))
1548
+ value = self.parse_map_value(ctx, key, check.not_none(check.not_none(key_tk.group).last()))
1549
+ if isinstance(value, YamlError):
1550
+ return value
1551
+ node1 = YamlNodeMakers.new_mapping_value_node(
1552
+ ctx,
1553
+ check.not_none(check.not_none(key_tk.group).last()),
1554
+ None,
1555
+ key,
1556
+ value,
1557
+ )
1558
+ if isinstance(node1, YamlError):
1559
+ return node1
1560
+ key_value_node = node1
1561
+ map_node = YamlNodeMakers.new_mapping_node(
1562
+ ctx,
1563
+ YamlParseToken(token=key_value_node.get_token()),
1564
+ False,
1565
+ key_value_node,
1566
+ )
1567
+ if isinstance(map_node, YamlError):
1568
+ return map_node
1569
+ tk: ta.Optional[YamlParseToken]
1570
+ if ctx.is_comment():
1571
+ tk = ctx.next_not_comment_token()
1572
+ else:
1573
+ tk = ctx.current_token()
1574
+ while YamlParseToken.column(tk) == YamlParseToken.column(key_tk):
1575
+ typ = YamlParseToken.type(tk)
1576
+ if ctx.is_flow and typ == YamlTokenType.SEQUENCE_END:
1577
+ # [
1578
+ # key: value
1579
+ # ] <=
1580
+ break
1581
+ if not self.is_map_token(check.not_none(tk)):
1582
+ return err_syntax('non-map value is specified', YamlParseToken.raw_token(tk))
1583
+ cm = self.parse_head_comment(ctx)
1584
+ if typ == YamlTokenType.MAPPING_END:
1585
+ # a: {
1586
+ # b: c
1587
+ # } <=
1588
+ ctx.go_next()
1589
+ break
1590
+ node2 = self.parse_map(ctx)
1591
+ if isinstance(node2, YamlError):
1592
+ return node2
1593
+ if len(node2.values) != 0:
1594
+ if (err := set_head_comment(cm, node2.values[0])) is not None:
1595
+ return err
1596
+ map_node.values.extend(node2.values)
1597
+ if node2.foot_comment is not None:
1598
+ map_node.values[len(map_node.values) - 1].foot_comment = node2.foot_comment
1599
+ tk = ctx.current_token()
1600
+ if ctx.is_comment():
1601
+ if YamlParseToken.column(key_tk) <= YamlParseToken.column(ctx.current_token()):
1602
+ # If the comment is in the same or deeper column as the last element column in map value,
1603
+ # treat it as a footer comment for the last element.
1604
+ if len(map_node.values) == 1:
1605
+ map_node.values[0].foot_comment = self.parse_foot_comment(ctx, YamlParseToken.column(key_tk))
1606
+ ast.BaseYamlNode.set_path(map_node.values[0].foot_comment, map_node.values[0].key.get_path())
1607
+ else:
1608
+ map_node.foot_comment = self.parse_foot_comment(ctx, YamlParseToken.column(key_tk))
1609
+ ast.BaseYamlNode.set_path(map_node.foot_comment, map_node.get_path())
1610
+ return map_node
1611
+
1612
+ def validate_map_key_value_next_token(self, ctx: YamlParsingContext, key_tk, tk: ta.Optional[YamlParseToken]) -> ta.Optional[YamlError]: # noqa
1613
+ if tk is None:
1614
+ return None
1615
+ if tk.column() <= key_tk.column():
1616
+ return None
1617
+ if ctx.is_comment():
1618
+ return None
1619
+ if (
1620
+ ctx.is_flow and
1621
+ (tk.type() == YamlTokenType.COLLECT_ENTRY or tk.type() == YamlTokenType.SEQUENCE_END)
1622
+ ):
1623
+ return None
1624
+ # a: b
1625
+ # c <= this token is invalid.
1626
+ return err_syntax('value is not allowed in this context. map key-value is pre-defined', tk.raw_token())
1627
+
1628
+ def is_map_token(self, tk: YamlParseToken) -> bool:
1629
+ if tk.group is None:
1630
+ return tk.type() == YamlTokenType.MAPPING_START or tk.type() == YamlTokenType.MAPPING_END
1631
+ g = tk.group
1632
+ return g.type == YamlParseTokenGroupType.MAP_KEY or g.type == YamlParseTokenGroupType.MAP_KEY_VALUE
1633
+
1634
+ def parse_map_key_value(self,
1635
+ ctx: YamlParsingContext,
1636
+ g: YamlParseTokenGroup,
1637
+ entry_tk: ta.Optional[YamlParseToken],
1638
+ ) -> YamlErrorOr[ast.MappingValueYamlNode]:
1639
+ if g.type != YamlParseTokenGroupType.MAP_KEY_VALUE:
1640
+ return err_syntax('unexpected map key-value pair', g.raw_token())
1641
+ if check.not_none(g.first()).group is None:
1642
+ return err_syntax('unexpected map key', g.raw_token())
1643
+ key_group = check.not_none(check.not_none(g.first()).group)
1644
+ key = self.parse_map_key(ctx.with_group(key_group), key_group)
1645
+ if isinstance(key, YamlError):
1646
+ return key
1647
+
1648
+ c = ctx.with_child(self.map_key_text(key))
1649
+ value = self.parse_token(c, g.last())
1650
+ if isinstance(value, YamlError):
1651
+ return value
1652
+ return YamlNodeMakers.new_mapping_value_node(c, check.not_none(key_group.last()), entry_tk, key, value)
1653
+
1654
+ def parse_map_key(self, ctx: YamlParsingContext, g: YamlParseTokenGroup) -> YamlErrorOr[ast.MapKeyYamlNode]:
1655
+ if g.type != YamlParseTokenGroupType.MAP_KEY:
1656
+ return err_syntax('unexpected map key', g.raw_token())
1657
+ if YamlParseToken.type(g.first()) == YamlTokenType.MAPPING_KEY:
1658
+ map_key_tk = check.not_none(g.first())
1659
+ if map_key_tk.group is not None:
1660
+ ctx = ctx.with_group(map_key_tk.group)
1661
+ key0 = YamlNodeMakers.new_mapping_key_node(ctx, map_key_tk)
1662
+ if isinstance(key0, YamlError):
1663
+ return key0
1664
+ ctx.go_next() # skip mapping key token
1665
+ if ctx.is_token_not_found():
1666
+ return err_syntax('could not find value for mapping key', YamlParseToken.raw_token(map_key_tk))
1667
+
1668
+ scalar0 = self.parse_scalar_value(ctx, ctx.current_token())
1669
+ if isinstance(scalar0, YamlError):
1670
+ return scalar0
1671
+ key0.value = scalar0
1672
+ key_text = self.map_key_text(scalar0)
1673
+ key_path = ctx.with_child(key_text).path
1674
+ key0.set_path(key_path)
1675
+ if (err := self.validate_map_key(
1676
+ ctx,
1677
+ check.not_none(key0.get_token()),
1678
+ key_path,
1679
+ check.not_none(g.last()),
1680
+ )) is not None:
1681
+ return err
1682
+ self.path_map[key_path] = key0
1683
+ return key0
1684
+ if YamlParseToken.type(g.last()) != YamlTokenType.MAPPING_VALUE:
1685
+ return err_syntax("expected map key-value delimiter ':'", YamlParseToken.raw_token(g.last()))
1686
+
1687
+ scalar1 = self.parse_scalar_value(ctx, g.first())
1688
+ if isinstance(scalar1, YamlError):
1689
+ return scalar1
1690
+ if not isinstance(scalar1, ast.MapKeyYamlNode):
1691
+ # FIXME: not possible
1692
+ return err_syntax(
1693
+ 'cannot take map-key node',
1694
+ check.not_none(scalar1).get_token(),
1695
+ )
1696
+ key1: ast.MapKeyYamlNode = ta.cast(ast.MapKeyYamlNode, scalar1)
1697
+ key_text = self.map_key_text(key1)
1698
+ key_path = ctx.with_child(key_text).path
1699
+ key1.set_path(key_path)
1700
+ if (err := self.validate_map_key(
1701
+ ctx,
1702
+ check.not_none(key1.get_token()),
1703
+ key_path,
1704
+ check.not_none(g.last()),
1705
+ )) is not None:
1706
+ return err
1707
+ self.path_map[key_path] = key1
1708
+ return key1
1709
+
1710
+ def validate_map_key(
1711
+ self,
1712
+ ctx: YamlParsingContext,
1713
+ tk: YamlToken,
1714
+ key_path: str,
1715
+ colon_tk: YamlParseToken,
1716
+ ) -> ta.Optional[YamlError]:
1717
+ if not self.allow_duplicate_map_key:
1718
+ if (n := self.path_map.get(key_path)) is not None:
1719
+ pos = check.not_none(n.get_token()).position
1720
+ return err_syntax(
1721
+ f'mapping key {tk.value!r} already defined at [{pos.line:d}:{pos.column:d}]',
1722
+ tk,
1723
+ )
1724
+ origin = self.remove_left_white_space(tk.origin)
1725
+ if ctx.is_flow:
1726
+ if tk.type == YamlTokenType.STRING:
1727
+ origin = self.remove_right_white_space(origin)
1728
+ if tk.position.line + self.new_line_character_num(origin) != colon_tk.line():
1729
+ return err_syntax('map key definition includes an implicit line break', tk)
1730
+ return None
1731
+ if (
1732
+ tk.type != YamlTokenType.STRING and
1733
+ tk.type != YamlTokenType.SINGLE_QUOTE and
1734
+ tk.type != YamlTokenType.DOUBLE_QUOTE
1735
+ ):
1736
+ return None
1737
+ if self.exists_new_line_character(origin):
1738
+ return err_syntax('unexpected key name', tk)
1739
+ return None
1740
+
1741
+ def remove_left_white_space(self, src: str) -> str:
1742
+ # CR or LF or CRLF
1743
+ return src.lstrip(' \r\n')
1744
+
1745
+ def remove_right_white_space(self, src: str) -> str:
1746
+ # CR or LF or CRLF
1747
+ return src.rstrip(' \r\n')
1748
+
1749
+ def exists_new_line_character(self, src: str) -> bool:
1750
+ return self.new_line_character_num(src) > 0
1751
+
1752
+ def new_line_character_num(self, src: str) -> int:
1753
+ num = 0
1754
+ i = -1
1755
+ while True:
1756
+ i += 1
1757
+ if not (i < len(src)):
1758
+ break
1759
+ if src[i] == '\r':
1760
+ if len(src) > i + 1 and src[i + 1] == '\n':
1761
+ i += 1
1762
+ num += 1
1763
+ elif src[i] == '\n':
1764
+ num += 1
1765
+ return num
1766
+
1767
+ def map_key_text(self, n: ta.Optional[ast.YamlNode]) -> str:
1768
+ if n is None:
1769
+ return ''
1770
+ nn = n
1771
+ if isinstance(nn, ast.MappingKeyYamlNode):
1772
+ return self.map_key_text(nn.value)
1773
+ if isinstance(nn, ast.TagYamlNode):
1774
+ return self.map_key_text(nn.value)
1775
+ if isinstance(nn, ast.AnchorYamlNode):
1776
+ return self.map_key_text(nn.value)
1777
+ if isinstance(nn, ast.AliasYamlNode):
1778
+ return ''
1779
+ return check.not_none(n.get_token()).value
1780
+
1781
+ def parse_map_value(
1782
+ self,
1783
+ ctx: YamlParsingContext,
1784
+ key: ast.MapKeyYamlNode,
1785
+ colon_tk: YamlParseToken,
1786
+ ) -> YamlErrorOr[ast.YamlNode]:
1787
+ tk = ctx.current_token()
1788
+ if tk is None:
1789
+ return YamlNodeMakers.new_null_node(ctx, ctx.add_null_value_token(colon_tk))
1790
+
1791
+ if ctx.is_comment():
1792
+ tk = ctx.next_not_comment_token()
1793
+ key_col = check.not_none(key.get_token()).position.column
1794
+ key_line = check.not_none(key.get_token()).position.line
1795
+
1796
+ if (
1797
+ YamlParseToken.column(tk) != key_col and
1798
+ YamlParseToken.line(tk) == key_line and
1799
+ (
1800
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.MAP_KEY or
1801
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.MAP_KEY_VALUE
1802
+ )
1803
+ ):
1804
+ # a: b:
1805
+ # ^
1806
+ #
1807
+ # a: b: c
1808
+ # ^
1809
+ return err_syntax('mapping value is not allowed in this context', YamlParseToken.raw_token(tk))
1810
+
1811
+ if YamlParseToken.column(tk) == key_col and self.is_map_token(check.not_none(tk)):
1812
+ # in this case,
1813
+ # ----
1814
+ # key: <value does not defined>
1815
+ # next
1816
+ return YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(colon_tk))
1817
+
1818
+ if (
1819
+ YamlParseToken.line(tk) == key_line and
1820
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME and
1821
+ YamlParseToken.column(ctx.next_token()) == key_col and
1822
+ self.is_map_token(check.not_none(ctx.next_token()))
1823
+ ):
1824
+ # in this case,
1825
+ # ----
1826
+ # key: &anchor
1827
+ # next
1828
+ group = YamlParseTokenGroup(
1829
+ type=YamlParseTokenGroupType.ANCHOR,
1830
+ tokens=[check.not_none(tk), ctx.create_implicit_null_token(check.not_none(tk))],
1831
+ )
1832
+ anchor = self.parse_anchor(ctx.with_group(group), group)
1833
+ if isinstance(anchor, YamlError):
1834
+ return anchor
1835
+ ctx.go_next()
1836
+ return anchor
1837
+
1838
+ if (
1839
+ YamlParseToken.column(tk) <= key_col and
1840
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME
1841
+ ):
1842
+ # key: <value does not defined>
1843
+ # &anchor
1844
+ return err_syntax('anchor is not allowed in this context', YamlParseToken.raw_token(tk))
1845
+ if YamlParseToken.column(tk) <= key_col and YamlParseToken.type(tk) == YamlTokenType.TAG:
1846
+ # key: <value does not defined>
1847
+ # !!tag
1848
+ return err_syntax('tag is not allowed in this context', YamlParseToken.raw_token(tk))
1849
+
1850
+ if YamlParseToken.column(tk) < key_col:
1851
+ # in this case,
1852
+ # ----
1853
+ # key: <value does not defined>
1854
+ # next
1855
+ return YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(colon_tk))
1856
+
1857
+ if (
1858
+ YamlParseToken.line(tk) == key_line and
1859
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME and
1860
+ YamlParseToken.column(ctx.next_token()) < key_col
1861
+ ):
1862
+ # in this case,
1863
+ # ----
1864
+ # key: &anchor
1865
+ # next
1866
+ group = YamlParseTokenGroup(
1867
+ type=YamlParseTokenGroupType.ANCHOR,
1868
+ tokens=[check.not_none(tk), ctx.create_implicit_null_token(check.not_none(tk))],
1869
+ )
1870
+ anchor = self.parse_anchor(ctx.with_group(group), group)
1871
+ if isinstance(anchor, YamlError):
1872
+ return anchor
1873
+ ctx.go_next()
1874
+ return anchor
1875
+
1876
+ value = self.parse_token(ctx, ctx.current_token())
1877
+ if isinstance(value, YamlError):
1878
+ return value
1879
+ if (err := self.validate_anchor_value_in_map_or_seq(value, key_col)) is not None:
1880
+ return err
1881
+ return value
1882
+
1883
+ def validate_anchor_value_in_map_or_seq(self, value: ast.YamlNode, col: int) -> ta.Optional[YamlError]:
1884
+ if not isinstance(value, ast.AnchorYamlNode):
1885
+ return None
1886
+ anchor: ast.AnchorYamlNode = value
1887
+ if not isinstance(anchor.value, ast.TagYamlNode):
1888
+ return None
1889
+ tag: ast.TagYamlNode = anchor.value
1890
+ anchor_tk = anchor.get_token()
1891
+ tag_tk = tag.get_token()
1892
+
1893
+ if anchor_tk.position.line == tag_tk.position.line:
1894
+ # key:
1895
+ # &anchor !!tag
1896
+ #
1897
+ # - &anchor !!tag
1898
+ return None
1899
+
1900
+ if tag_tk.position.column <= col:
1901
+ # key: &anchor
1902
+ # !!tag
1903
+ #
1904
+ # - &anchor
1905
+ # !!tag
1906
+ return err_syntax('tag is not allowed in this context', tag_tk)
1907
+ return None
1908
+
1909
+ def parse_anchor(self, ctx: YamlParsingContext, g: YamlParseTokenGroup) -> YamlErrorOr[ast.AnchorYamlNode]:
1910
+ anchor_name_group = check.not_none(check.not_none(g.first()).group)
1911
+ anchor = self.parse_anchor_name(ctx.with_group(anchor_name_group))
1912
+ if isinstance(anchor, YamlError):
1913
+ return anchor
1914
+ ctx.go_next()
1915
+ if ctx.is_token_not_found():
1916
+ return err_syntax('could not find anchor value', anchor.get_token())
1917
+
1918
+ value = self.parse_token(ctx, ctx.current_token())
1919
+ if isinstance(value, YamlError):
1920
+ return value
1921
+ if isinstance(value, ast.AnchorYamlNode):
1922
+ return err_syntax('anchors cannot be used consecutively', value.get_token())
1923
+ anchor.value = value
1924
+ return anchor
1925
+
1926
+ def parse_anchor_name(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.AnchorYamlNode]:
1927
+ anchor = YamlNodeMakers.new_anchor_node(ctx, ctx.current_token())
1928
+ if isinstance(anchor, YamlError):
1929
+ return anchor
1930
+ ctx.go_next()
1931
+ if ctx.is_token_not_found():
1932
+ return err_syntax('could not find anchor value', anchor.get_token())
1933
+
1934
+ anchor_name = self.parse_scalar_value(ctx, ctx.current_token())
1935
+ if isinstance(anchor_name, YamlError):
1936
+ return anchor_name
1937
+ if anchor_name is None:
1938
+ return err_syntax(
1939
+ 'unexpected anchor. anchor name is not scalar value',
1940
+ YamlParseToken.raw_token(ctx.current_token()),
1941
+ )
1942
+ anchor.name = anchor_name
1943
+ return anchor
1944
+
1945
+ def parse_alias(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.AliasYamlNode]:
1946
+ alias = YamlNodeMakers.new_alias_node(ctx, ctx.current_token())
1947
+ if isinstance(alias, YamlError):
1948
+ return alias
1949
+ ctx.go_next()
1950
+ if ctx.is_token_not_found():
1951
+ return err_syntax('could not find alias value', alias.get_token())
1952
+
1953
+ alias_name = self.parse_scalar_value(ctx, ctx.current_token())
1954
+ if isinstance(alias_name, YamlError):
1955
+ return alias_name
1956
+ if alias_name is None:
1957
+ return err_syntax(
1958
+ 'unexpected alias. alias name is not scalar value',
1959
+ YamlParseToken.raw_token(ctx.current_token()),
1960
+ )
1961
+ alias.value = alias_name
1962
+ return alias
1963
+
1964
+ def parse_literal(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.LiteralYamlNode]:
1965
+ node = YamlNodeMakers.new_literal_node(ctx, ctx.current_token())
1966
+ if isinstance(node, YamlError):
1967
+ return node
1968
+ ctx.go_next() # skip literal/folded token
1969
+
1970
+ tk = ctx.current_token()
1971
+ if tk is None:
1972
+ value0 = YamlNodeMakers.new_string_node(
1973
+ ctx,
1974
+ YamlParseToken(token=new_yaml_token('', '', node.start.position)),
1975
+ )
1976
+ if isinstance(value0, YamlError):
1977
+ return value0
1978
+ node.value = value0
1979
+ return node
1980
+ value1 = self.parse_token(ctx, tk)
1981
+ if isinstance(value1, YamlError):
1982
+ return value1
1983
+ if not isinstance(s := value1, ast.StringYamlNode):
1984
+ return err_syntax('unexpected token. required string token', value1.get_token())
1985
+ node.value = s
1986
+ return node
1987
+
1988
+ def parse_scalar_tag(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.TagYamlNode]:
1989
+ tag = self.parse_tag(ctx)
1990
+ if isinstance(tag, YamlError):
1991
+ return tag
1992
+ if tag.value is None:
1993
+ return err_syntax('specified not scalar tag', tag.get_token())
1994
+ if not isinstance(tag.value, ast.ScalarYamlNode):
1995
+ return err_syntax('specified not scalar tag', tag.get_token())
1996
+ return tag
1997
+
1998
+ def parse_tag(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.TagYamlNode]:
1999
+ tag_tk = ctx.current_token()
2000
+ tag_raw_tk = YamlParseToken.raw_token(tag_tk)
2001
+ node = YamlNodeMakers.new_tag_node(ctx, tag_tk)
2002
+ if isinstance(node, YamlError):
2003
+ return node
2004
+ ctx.go_next()
2005
+
2006
+ comment = self.parse_head_comment(ctx)
2007
+
2008
+ tag_value: ast.YamlNode
2009
+ if self.secondary_tag_directive is not None:
2010
+ value0 = YamlNodeMakers.new_string_node(ctx, ctx.current_token())
2011
+ if isinstance(value0, YamlError):
2012
+ return value0
2013
+ tag_value = value0
2014
+ node.directive = self.secondary_tag_directive
2015
+ else:
2016
+ value1 = self.parse_tag_value(ctx, check.not_none(tag_raw_tk), ctx.current_token())
2017
+ if isinstance(value1, YamlError):
2018
+ return value1
2019
+ tag_value = check.not_none(value1)
2020
+ if (err := set_head_comment(comment, tag_value)) is not None:
2021
+ return err
2022
+ node.value = tag_value
2023
+ return node
2024
+
2025
+ def parse_tag_value(
2026
+ self,
2027
+ ctx: YamlParsingContext,
2028
+ tag_raw_tk: YamlToken,
2029
+ tk: ta.Optional[YamlParseToken],
2030
+ ) -> YamlErrorOr[ta.Optional[ast.YamlNode]]:
2031
+ if tk is None:
2032
+ return YamlNodeMakers.new_null_node(ctx, ctx.create_implicit_null_token(YamlParseToken(token=tag_raw_tk)))
2033
+ if tag_raw_tk.value in (
2034
+ YamlReservedTagKeywords.MAPPING,
2035
+ YamlReservedTagKeywords.SET,
2036
+ ):
2037
+ if not self.is_map_token(tk):
2038
+ return err_syntax('could not find map', tk.raw_token())
2039
+ if tk.type() == YamlTokenType.MAPPING_START:
2040
+ return self.parse_flow_map(ctx.with_flow(True))
2041
+ return self.parse_map(ctx)
2042
+ elif tag_raw_tk.value in (
2043
+ YamlReservedTagKeywords.INTEGER,
2044
+ YamlReservedTagKeywords.FLOAT,
2045
+ YamlReservedTagKeywords.STRING,
2046
+ YamlReservedTagKeywords.BINARY,
2047
+ YamlReservedTagKeywords.TIMESTAMP,
2048
+ YamlReservedTagKeywords.BOOLEAN,
2049
+ YamlReservedTagKeywords.NULL,
2050
+ ):
2051
+ if tk.group_type() == YamlParseTokenGroupType.LITERAL or tk.group_type() == YamlParseTokenGroupType.FOLDED:
2052
+ return self.parse_literal(ctx.with_group(check.not_none(tk.group)))
2053
+ elif tk.type() == YamlTokenType.COLLECT_ENTRY or tk.type() == YamlTokenType.MAPPING_VALUE:
2054
+ return YamlNodeMakers.new_tag_default_scalar_value_node(ctx, tag_raw_tk)
2055
+ scalar = self.parse_scalar_value(ctx, tk)
2056
+ if isinstance(scalar, YamlError):
2057
+ return scalar
2058
+ ctx.go_next()
2059
+ return scalar
2060
+ elif tag_raw_tk.value in (
2061
+ YamlReservedTagKeywords.SEQUENCE,
2062
+ YamlReservedTagKeywords.ORDERED_MAP,
2063
+ ):
2064
+ if tk.type() == YamlTokenType.SEQUENCE_START:
2065
+ return self.parse_flow_sequence(ctx.with_flow(True))
2066
+ return self.parse_sequence(ctx)
2067
+ return self.parse_token(ctx, tk)
2068
+
2069
+ def parse_flow_sequence(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.SequenceYamlNode]:
2070
+ node = YamlNodeMakers.new_sequence_node(ctx, ctx.current_token(), True)
2071
+ if isinstance(node, YamlError):
2072
+ return node
2073
+ ctx.go_next() # skip SequenceStart token
2074
+
2075
+ is_first = True
2076
+ while ctx.next():
2077
+ tk = ctx.current_token()
2078
+ if YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_END:
2079
+ node.end = YamlParseToken.raw_token(tk)
2080
+ break
2081
+
2082
+ entry_tk: ta.Optional[YamlParseToken] = None
2083
+ if YamlParseToken.type(tk) == YamlTokenType.COLLECT_ENTRY:
2084
+ if is_first:
2085
+ return err_syntax("expected sequence element, but found ','", YamlParseToken.raw_token(tk))
2086
+ entry_tk = tk
2087
+ ctx.go_next()
2088
+ elif not is_first:
2089
+ return err_syntax("',' or ']' must be specified", YamlParseToken.raw_token(tk))
2090
+
2091
+ if YamlParseToken.type(tk := ctx.current_token()) == YamlTokenType.SEQUENCE_END:
2092
+ # this case is here: "[ elem, ]".
2093
+ # In this case, ignore the last element and break sequence parsing.
2094
+ node.end = YamlParseToken.raw_token(tk)
2095
+ break
2096
+
2097
+ if ctx.is_token_not_found():
2098
+ break
2099
+
2100
+ ctx = ctx.with_index(len(node.values))
2101
+ value = self.parse_token(ctx, ctx.current_token())
2102
+ if isinstance(value, YamlError):
2103
+ return value
2104
+ node.values.append(value)
2105
+ seq_entry = ast.sequence_entry(
2106
+ entry_tk.raw_token() if entry_tk is not None else None,
2107
+ value,
2108
+ None,
2109
+ )
2110
+ if (err := set_line_comment(ctx, seq_entry, entry_tk)) is not None:
2111
+ return err
2112
+ seq_entry.set_path(ctx.path)
2113
+ node.entries.append(seq_entry)
2114
+
2115
+ is_first = False
2116
+ if node.end is None:
2117
+ return err_syntax("sequence end token ']' not found", node.start)
2118
+ ctx.go_next() # skip sequence end token.
2119
+ return node
2120
+
2121
+ def parse_sequence(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.SequenceYamlNode]:
2122
+ seq_tk = ctx.current_token()
2123
+ seq_node = YamlNodeMakers.new_sequence_node(ctx, seq_tk, False)
2124
+ if isinstance(seq_node, YamlError):
2125
+ return seq_node
2126
+
2127
+ tk = seq_tk
2128
+ while (
2129
+ YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_ENTRY and
2130
+ YamlParseToken.column(tk) == YamlParseToken.column(seq_tk)
2131
+ ):
2132
+ head_comment = self.parse_head_comment(ctx)
2133
+ ctx.go_next() # skip sequence entry token
2134
+
2135
+ ctx = ctx.with_index(len(seq_node.values))
2136
+ value = self.parse_sequence_value(ctx, check.not_none(seq_tk))
2137
+ if isinstance(value, YamlError):
2138
+ return value
2139
+ seq_entry = ast.sequence_entry(YamlParseToken.raw_token(seq_tk), value, head_comment)
2140
+ if (err := set_line_comment(ctx, seq_entry, seq_tk)) is not None:
2141
+ return err
2142
+ seq_entry.set_path(ctx.path)
2143
+ seq_node.value_head_comments.append(head_comment)
2144
+ seq_node.values.append(value)
2145
+ seq_node.entries.append(seq_entry)
2146
+
2147
+ if ctx.is_comment():
2148
+ tk = ctx.next_not_comment_token()
2149
+ else:
2150
+ tk = ctx.current_token()
2151
+ if ctx.is_comment():
2152
+ if YamlParseToken.column(seq_tk) <= YamlParseToken.column(ctx.current_token()):
2153
+ # If the comment is in the same or deeper column as the last element column in sequence value,
2154
+ # treat it as a footer comment for the last element.
2155
+ seq_node.foot_comment = self.parse_foot_comment(ctx, YamlParseToken.column(seq_tk))
2156
+ if len(seq_node.values) != 0:
2157
+ check.not_none(seq_node.foot_comment).set_path(
2158
+ check.not_none(seq_node.values[len(seq_node.values) - 1]).get_path(),
2159
+ )
2160
+ return seq_node
2161
+
2162
+ def parse_sequence_value(self, ctx: YamlParsingContext, seq_tk: YamlParseToken) -> YamlErrorOr[ast.YamlNode]:
2163
+ tk = ctx.current_token()
2164
+ if tk is None:
2165
+ return YamlNodeMakers.new_null_node(ctx, ctx.add_null_value_token(seq_tk))
2166
+
2167
+ if ctx.is_comment():
2168
+ tk = ctx.next_not_comment_token()
2169
+ seq_col = seq_tk.column()
2170
+ seq_line = seq_tk.line()
2171
+
2172
+ if YamlParseToken.column(tk) == seq_col and YamlParseToken.type(tk) == YamlTokenType.SEQUENCE_ENTRY:
2173
+ # in this case,
2174
+ # ----
2175
+ # - <value does not defined>
2176
+ # -
2177
+ return YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(seq_tk))
2178
+
2179
+ if (
2180
+ YamlParseToken.line(tk) == seq_line and
2181
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME and
2182
+ YamlParseToken.column(ctx.next_token()) == seq_col and
2183
+ YamlParseToken.type(ctx.next_token()) == YamlTokenType.SEQUENCE_ENTRY
2184
+ ):
2185
+ # in this case,
2186
+ # ----
2187
+ # - &anchor
2188
+ # -
2189
+ group = YamlParseTokenGroup(
2190
+ type=YamlParseTokenGroupType.ANCHOR,
2191
+ tokens=[check.not_none(tk), ctx.create_implicit_null_token(check.not_none(tk))],
2192
+ )
2193
+ anchor = self.parse_anchor(ctx.with_group(group), group)
2194
+ if isinstance(anchor, YamlError):
2195
+ return anchor
2196
+ ctx.go_next()
2197
+ return anchor
2198
+
2199
+ if (
2200
+ YamlParseToken.column(tk) <= seq_col and
2201
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME
2202
+ ):
2203
+ # - <value does not defined>
2204
+ # &anchor
2205
+ return err_syntax('anchor is not allowed in this sequence context', YamlParseToken.raw_token(tk))
2206
+ if YamlParseToken.column(tk) <= seq_col and YamlParseToken.type(tk) == YamlTokenType.TAG:
2207
+ # - <value does not defined>
2208
+ # !!tag
2209
+ return err_syntax('tag is not allowed in this sequence context', YamlParseToken.raw_token(tk))
2210
+
2211
+ if YamlParseToken.column(tk) < seq_col:
2212
+ # in this case,
2213
+ # ----
2214
+ # - <value does not defined>
2215
+ # next
2216
+ return YamlNodeMakers.new_null_node(ctx, ctx.insert_null_token(seq_tk))
2217
+
2218
+ if (
2219
+ YamlParseToken.line(tk) == seq_line and
2220
+ YamlParseToken.group_type(tk) == YamlParseTokenGroupType.ANCHOR_NAME and
2221
+ YamlParseToken.column(ctx.next_token()) < seq_col
2222
+ ):
2223
+ # in this case,
2224
+ # ----
2225
+ # - &anchor
2226
+ # next
2227
+ group = YamlParseTokenGroup(
2228
+ type=YamlParseTokenGroupType.ANCHOR,
2229
+ tokens=[check.not_none(tk), ctx.create_implicit_null_token(check.not_none(tk))],
2230
+ )
2231
+ anchor = self.parse_anchor(ctx.with_group(group), group)
2232
+ if isinstance(anchor, YamlError):
2233
+ return anchor
2234
+ ctx.go_next()
2235
+ return anchor
2236
+
2237
+ value = self.parse_token(ctx, ctx.current_token())
2238
+ if isinstance(value, YamlError):
2239
+ return value
2240
+ if (err := self.validate_anchor_value_in_map_or_seq(value, seq_col)) is not None:
2241
+ return err
2242
+ return value
2243
+
2244
+ def parse_directive(self, ctx: YamlParsingContext, g: YamlParseTokenGroup) -> YamlErrorOr[ast.DirectiveYamlNode]:
2245
+ directive_name_group = check.not_none(check.not_none(g.first()).group)
2246
+ directive = self.parse_directive_name(ctx.with_group(directive_name_group))
2247
+ if isinstance(directive, YamlError):
2248
+ return directive
2249
+
2250
+ if directive.name == 'YAML':
2251
+ if len(g.tokens) != 2:
2252
+ return err_syntax('unexpected format YAML directive', YamlParseToken.raw_token(g.first()))
2253
+ value_tk = g.tokens[1]
2254
+ value_raw_tk = check.not_none(value_tk.raw_token())
2255
+ value0 = value_raw_tk.value
2256
+ ver = YAML_VERSION_MAP.get(value0)
2257
+ if ver is None:
2258
+ return err_syntax(f'unknown YAML version {value0!r}', value_raw_tk)
2259
+ if self.yaml_version != '':
2260
+ return err_syntax('YAML version has already been specified', value_raw_tk)
2261
+ self.yaml_version = ver
2262
+ version_node = YamlNodeMakers.new_string_node(ctx, value_tk)
2263
+ if isinstance(version_node, YamlError):
2264
+ return version_node
2265
+ directive.values.append(version_node)
2266
+ elif directive.name == 'TAG':
2267
+ if len(g.tokens) != 3:
2268
+ return err_syntax('unexpected format TAG directive', YamlParseToken.raw_token(g.first()))
2269
+ tag_key = YamlNodeMakers.new_string_node(ctx, g.tokens[1])
2270
+ if isinstance(tag_key, YamlError):
2271
+ return tag_key
2272
+ if tag_key.value == '!!':
2273
+ self.secondary_tag_directive = directive
2274
+ tag_value = YamlNodeMakers.new_string_node(ctx, g.tokens[2])
2275
+ if isinstance(tag_value, YamlError):
2276
+ return tag_value
2277
+ directive.values.extend([tag_key, tag_value])
2278
+ elif len(g.tokens) > 1:
2279
+ for tk in g.tokens[1:]:
2280
+ value1 = YamlNodeMakers.new_string_node(ctx, tk)
2281
+ if isinstance(value1, YamlError):
2282
+ return value1
2283
+ directive.values.append(value1)
2284
+ return directive
2285
+
2286
+ def parse_directive_name(self, ctx: YamlParsingContext) -> YamlErrorOr[ast.DirectiveYamlNode]:
2287
+ directive = YamlNodeMakers.new_directive_node(ctx, ctx.current_token())
2288
+ if isinstance(directive, YamlError):
2289
+ return directive
2290
+ ctx.go_next()
2291
+ if ctx.is_token_not_found():
2292
+ return err_syntax('could not find directive value', directive.get_token())
2293
+
2294
+ directive_name = self.parse_scalar_value(ctx, ctx.current_token())
2295
+ if isinstance(directive_name, YamlError):
2296
+ return directive_name
2297
+ if directive_name is None:
2298
+ return err_syntax(
2299
+ 'unexpected directive. directive name is not scalar value',
2300
+ YamlParseToken.raw_token(ctx.current_token()),
2301
+ )
2302
+ directive.name = directive_name
2303
+ return directive
2304
+
2305
+ def parse_comment(self, ctx: YamlParsingContext) -> YamlErrorOr[ta.Optional[ast.YamlNode]]:
2306
+ cm = self.parse_head_comment(ctx)
2307
+ if ctx.is_token_not_found():
2308
+ return cm
2309
+ node = self.parse_token(ctx, ctx.current_token())
2310
+ if isinstance(node, YamlError):
2311
+ return node
2312
+ if (err := set_head_comment(cm, node)) is not None:
2313
+ return err
2314
+ return node
2315
+
2316
+ def parse_head_comment(self, ctx: YamlParsingContext) -> ta.Optional[ast.CommentGroupYamlNode]:
2317
+ tks: ta.List[ta.Optional[YamlToken]] = []
2318
+ while ctx.is_comment():
2319
+ tks.append(YamlParseToken.raw_token(ctx.current_token()))
2320
+ ctx.go_next()
2321
+ if len(tks) == 0:
2322
+ return None
2323
+ return ast.comment_group(tks)
2324
+
2325
+ def parse_foot_comment(self, ctx: YamlParsingContext, col: int) -> ta.Optional[ast.CommentGroupYamlNode]:
2326
+ tks: ta.List[ta.Optional[YamlToken]] = []
2327
+ while ctx.is_comment() and col <= YamlParseToken.column(ctx.current_token()):
2328
+ tks.append(YamlParseToken.raw_token(ctx.current_token()))
2329
+ ctx.go_next()
2330
+ if len(tks) == 0:
2331
+ return None
2332
+ return ast.comment_group(tks)