25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

863 satır
36 KiB

  1. from __future__ import annotations
  2. # The following YAML grammar is LL(1) and is parsed by a recursive descent
  3. # parser.
  4. #
  5. # stream ::= STREAM-START implicit_document? explicit_document*
  6. # STREAM-END
  7. # implicit_document ::= block_node DOCUMENT-END*
  8. # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
  9. # block_node_or_indentless_sequence ::=
  10. # ALIAS
  11. # | properties (block_content |
  12. # indentless_block_sequence)?
  13. # | block_content
  14. # | indentless_block_sequence
  15. # block_node ::= ALIAS
  16. # | properties block_content?
  17. # | block_content
  18. # flow_node ::= ALIAS
  19. # | properties flow_content?
  20. # | flow_content
  21. # properties ::= TAG ANCHOR? | ANCHOR TAG?
  22. # block_content ::= block_collection | flow_collection | SCALAR
  23. # flow_content ::= flow_collection | SCALAR
  24. # block_collection ::= block_sequence | block_mapping
  25. # flow_collection ::= flow_sequence | flow_mapping
  26. # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
  27. # BLOCK-END
  28. # indentless_sequence ::= (BLOCK-ENTRY block_node?)+
  29. # block_mapping ::= BLOCK-MAPPING_START
  30. # ((KEY block_node_or_indentless_sequence?)?
  31. # (VALUE block_node_or_indentless_sequence?)?)*
  32. # BLOCK-END
  33. # flow_sequence ::= FLOW-SEQUENCE-START
  34. # (flow_sequence_entry FLOW-ENTRY)*
  35. # flow_sequence_entry?
  36. # FLOW-SEQUENCE-END
  37. # flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
  38. # flow_mapping ::= FLOW-MAPPING-START
  39. # (flow_mapping_entry FLOW-ENTRY)*
  40. # flow_mapping_entry?
  41. # FLOW-MAPPING-END
  42. # flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
  43. #
  44. # FIRST sets:
  45. #
  46. # stream: { STREAM-START <}
  47. # explicit_document: { DIRECTIVE DOCUMENT-START }
  48. # implicit_document: FIRST(block_node)
  49. # block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START
  50. # BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
  51. # flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
  52. # block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START
  53. # FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
  54. # flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
  55. # block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
  56. # flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
  57. # block_sequence: { BLOCK-SEQUENCE-START }
  58. # block_mapping: { BLOCK-MAPPING-START }
  59. # block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR
  60. # BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START
  61. # FLOW-MAPPING-START BLOCK-ENTRY }
  62. # indentless_sequence: { ENTRY }
  63. # flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
  64. # flow_sequence: { FLOW-SEQUENCE-START }
  65. # flow_mapping: { FLOW-MAPPING-START }
  66. # flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
  67. # FLOW-MAPPING-START KEY }
  68. # flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
  69. # FLOW-MAPPING-START KEY }
  70. # need to have full path with import, as pkg_resources tries to load parser.py in __init__.py
  71. # only to not do anything with the package afterwards
  72. # and for Jython too
  73. from ruamel.yaml.error import MarkedYAMLError
  74. from ruamel.yaml.tokens import * # NOQA
  75. from ruamel.yaml.events import * # NOQA
  76. from ruamel.yaml.scanner import Scanner, RoundTripScanner, ScannerError # NOQA
  77. from ruamel.yaml.scanner import BlankLineComment
  78. from ruamel.yaml.comments import C_PRE, C_POST, C_SPLIT_ON_FIRST_BLANK
  79. from ruamel.yaml.compat import nprint, nprintf # NOQA
  80. from ruamel.yaml.tag import Tag
  81. if False: # MYPY
  82. from typing import Any, Dict, Optional, List, Optional # NOQA
  83. __all__ = ['Parser', 'RoundTripParser', 'ParserError']
  84. def xprintf(*args: Any, **kw: Any) -> Any:
  85. return nprintf(*args, **kw)
  86. pass
  87. class ParserError(MarkedYAMLError):
  88. pass
  89. class Parser:
  90. # Since writing a recursive-descendant parser is a straightforward task, we
  91. # do not give many comments here.
  92. DEFAULT_TAGS = {'!': '!', '!!': 'tag:yaml.org,2002:'}
  93. def __init__(self, loader: Any) -> None:
  94. self.loader = loader
  95. if self.loader is not None and getattr(self.loader, '_parser', None) is None:
  96. self.loader._parser = self
  97. self.reset_parser()
  98. def reset_parser(self) -> None:
  99. # Reset the state attributes (to clear self-references)
  100. self.current_event = self.last_event = None
  101. self.tag_handles: Dict[Any, Any] = {}
  102. self.states: List[Any] = []
  103. self.marks: List[Any] = []
  104. self.state: Any = self.parse_stream_start
  105. def dispose(self) -> None:
  106. self.reset_parser()
  107. @property
  108. def scanner(self) -> Any:
  109. if hasattr(self.loader, 'typ'):
  110. return self.loader.scanner
  111. return self.loader._scanner
  112. @property
  113. def resolver(self) -> Any:
  114. if hasattr(self.loader, 'typ'):
  115. return self.loader.resolver
  116. return self.loader._resolver
  117. def check_event(self, *choices: Any) -> bool:
  118. # Check the type of the next event.
  119. if self.current_event is None:
  120. if self.state:
  121. self.current_event = self.state()
  122. if self.current_event is not None:
  123. if not choices:
  124. return True
  125. for choice in choices:
  126. if isinstance(self.current_event, choice):
  127. return True
  128. return False
  129. def peek_event(self) -> Any:
  130. # Get the next event.
  131. if self.current_event is None:
  132. if self.state:
  133. self.current_event = self.state()
  134. return self.current_event
  135. def get_event(self) -> Any:
  136. # Get the next event and proceed further.
  137. if self.current_event is None:
  138. if self.state:
  139. self.current_event = self.state()
  140. # assert self.current_event is not None
  141. # if self.current_event.end_mark.line != self.peek_event().start_mark.line:
  142. xprintf('get_event', repr(self.current_event), self.peek_event().start_mark.line)
  143. self.last_event = value = self.current_event
  144. self.current_event = None
  145. return value
  146. # stream ::= STREAM-START implicit_document? explicit_document*
  147. # STREAM-END
  148. # implicit_document ::= block_node DOCUMENT-END*
  149. # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
  150. def parse_stream_start(self) -> Any:
  151. # Parse the stream start.
  152. token = self.scanner.get_token()
  153. self.move_token_comment(token)
  154. event = StreamStartEvent(token.start_mark, token.end_mark, encoding=token.encoding)
  155. # Prepare the next state.
  156. self.state = self.parse_implicit_document_start
  157. return event
  158. def parse_implicit_document_start(self) -> Any:
  159. # Parse an implicit document.
  160. if not self.scanner.check_token(DirectiveToken, DocumentStartToken, StreamEndToken):
  161. # don't need copy, as an implicit tag doesn't add tag_handles
  162. self.tag_handles = self.DEFAULT_TAGS
  163. token = self.scanner.peek_token()
  164. start_mark = end_mark = token.start_mark
  165. event = DocumentStartEvent(start_mark, end_mark, explicit=False)
  166. # Prepare the next state.
  167. self.states.append(self.parse_document_end)
  168. self.state = self.parse_block_node
  169. return event
  170. else:
  171. return self.parse_document_start()
  172. def parse_document_start(self) -> Any:
  173. # Parse any extra document end indicators.
  174. while self.scanner.check_token(DocumentEndToken):
  175. self.scanner.get_token()
  176. # Parse an explicit document.
  177. if not self.scanner.check_token(StreamEndToken):
  178. version, tags = self.process_directives()
  179. if not self.scanner.check_token(DocumentStartToken):
  180. raise ParserError(
  181. None,
  182. None,
  183. "expected '<document start>', "
  184. f'but found {self.scanner.peek_token().id,!r}',
  185. self.scanner.peek_token().start_mark,
  186. )
  187. token = self.scanner.get_token()
  188. start_mark = token.start_mark
  189. end_mark = token.end_mark
  190. # if self.loader is not None and \
  191. # end_mark.line != self.scanner.peek_token().start_mark.line:
  192. # self.loader.scalar_after_indicator = False
  193. event: Any = DocumentStartEvent(
  194. start_mark,
  195. end_mark,
  196. explicit=True,
  197. version=version,
  198. tags=tags,
  199. comment=token.comment,
  200. )
  201. self.states.append(self.parse_document_end)
  202. self.state = self.parse_document_content
  203. else:
  204. # Parse the end of the stream.
  205. token = self.scanner.get_token()
  206. event = StreamEndEvent(token.start_mark, token.end_mark, comment=token.comment)
  207. assert not self.states
  208. assert not self.marks
  209. self.state = None
  210. return event
  211. def parse_document_end(self) -> Any:
  212. # Parse the document end.
  213. token = self.scanner.peek_token()
  214. start_mark = end_mark = token.start_mark
  215. explicit = False
  216. if self.scanner.check_token(DocumentEndToken):
  217. token = self.scanner.get_token()
  218. # if token.end_mark.line != self.peek_event().start_mark.line:
  219. pt = self.scanner.peek_token()
  220. if not isinstance(pt, StreamEndToken) and (
  221. token.end_mark.line == pt.start_mark.line
  222. ):
  223. raise ParserError(
  224. None,
  225. None,
  226. 'found non-comment content after document end marker, '
  227. f'{self.scanner.peek_token().id,!r}',
  228. self.scanner.peek_token().start_mark,
  229. )
  230. end_mark = token.end_mark
  231. explicit = True
  232. event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)
  233. # Prepare the next state.
  234. if self.resolver.processing_version == (1, 1):
  235. self.state = self.parse_document_start
  236. else:
  237. if explicit:
  238. # found a document end marker, can be followed by implicit document
  239. self.state = self.parse_implicit_document_start
  240. else:
  241. self.state = self.parse_document_start
  242. return event
  243. def parse_document_content(self) -> Any:
  244. if self.scanner.check_token(
  245. DirectiveToken, DocumentStartToken, DocumentEndToken, StreamEndToken,
  246. ):
  247. event = self.process_empty_scalar(self.scanner.peek_token().start_mark)
  248. self.state = self.states.pop()
  249. return event
  250. else:
  251. return self.parse_block_node()
  252. def process_directives(self) -> Any:
  253. yaml_version = None
  254. self.tag_handles = {}
  255. while self.scanner.check_token(DirectiveToken):
  256. token = self.scanner.get_token()
  257. if token.name == 'YAML':
  258. if yaml_version is not None:
  259. raise ParserError(
  260. None, None, 'found duplicate YAML directive', token.start_mark,
  261. )
  262. major, minor = token.value
  263. if major != 1:
  264. raise ParserError(
  265. None,
  266. None,
  267. 'found incompatible YAML document (version 1.* is required)',
  268. token.start_mark,
  269. )
  270. yaml_version = token.value
  271. elif token.name == 'TAG':
  272. handle, prefix = token.value
  273. if handle in self.tag_handles:
  274. raise ParserError(
  275. None, None, f'duplicate tag handle {handle!r}', token.start_mark,
  276. )
  277. self.tag_handles[handle] = prefix
  278. if bool(self.tag_handles):
  279. value: Any = (yaml_version, self.tag_handles.copy())
  280. else:
  281. value = yaml_version, None
  282. if self.loader is not None and hasattr(self.loader, 'tags'):
  283. # ToDo: this is used to keep a single loaded file from losing its version
  284. # info, but it affects following versions that have no explicit directive
  285. self.loader.version = yaml_version
  286. if self.loader.tags is None:
  287. self.loader.tags = {}
  288. for k in self.tag_handles:
  289. self.loader.tags[k] = self.tag_handles[k]
  290. self.loader.doc_infos[-1].tags.append((k, self.tag_handles[k]))
  291. for key in self.DEFAULT_TAGS:
  292. if key not in self.tag_handles:
  293. self.tag_handles[key] = self.DEFAULT_TAGS[key]
  294. return value
  295. # block_node_or_indentless_sequence ::= ALIAS
  296. # | properties (block_content | indentless_block_sequence)?
  297. # | block_content
  298. # | indentless_block_sequence
  299. # block_node ::= ALIAS
  300. # | properties block_content?
  301. # | block_content
  302. # flow_node ::= ALIAS
  303. # | properties flow_content?
  304. # | flow_content
  305. # properties ::= TAG ANCHOR? | ANCHOR TAG?
  306. # block_content ::= block_collection | flow_collection | SCALAR
  307. # flow_content ::= flow_collection | SCALAR
  308. # block_collection ::= block_sequence | block_mapping
  309. # flow_collection ::= flow_sequence | flow_mapping
  310. def parse_block_node(self) -> Any:
  311. return self.parse_node(block=True)
  312. def parse_flow_node(self) -> Any:
  313. return self.parse_node()
  314. def parse_block_node_or_indentless_sequence(self) -> Any:
  315. return self.parse_node(block=True, indentless_sequence=True)
  316. # def transform_tag(self, handle: Any, suffix: Any) -> Any:
  317. # return self.tag_handles[handle] + suffix
  318. def select_tag_transform(self, tag: Tag) -> None:
  319. if tag is None:
  320. return
  321. tag.select_transform(False)
  322. def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> Any:
  323. if self.scanner.check_token(AliasToken):
  324. token = self.scanner.get_token()
  325. event: Any = AliasEvent(token.value, token.start_mark, token.end_mark)
  326. self.state = self.states.pop()
  327. return event
  328. anchor = None
  329. tag = None
  330. start_mark = end_mark = tag_mark = None
  331. if self.scanner.check_token(AnchorToken):
  332. token = self.scanner.get_token()
  333. self.move_token_comment(token)
  334. start_mark = token.start_mark
  335. end_mark = token.end_mark
  336. anchor = token.value
  337. if self.scanner.check_token(TagToken):
  338. token = self.scanner.get_token()
  339. tag_mark = token.start_mark
  340. end_mark = token.end_mark
  341. # tag = token.value
  342. tag = Tag(
  343. handle=token.value[0], suffix=token.value[1], handles=self.tag_handles,
  344. )
  345. elif self.scanner.check_token(TagToken):
  346. token = self.scanner.get_token()
  347. try:
  348. self.move_token_comment(token)
  349. except NotImplementedError:
  350. pass
  351. start_mark = tag_mark = token.start_mark
  352. end_mark = token.end_mark
  353. # tag = token.value
  354. tag = Tag(handle=token.value[0], suffix=token.value[1], handles=self.tag_handles)
  355. if self.scanner.check_token(AnchorToken):
  356. token = self.scanner.get_token()
  357. start_mark = tag_mark = token.start_mark
  358. end_mark = token.end_mark
  359. anchor = token.value
  360. if tag is not None:
  361. self.select_tag_transform(tag)
  362. if tag.check_handle():
  363. raise ParserError(
  364. 'while parsing a node',
  365. start_mark,
  366. f'found undefined tag handle {tag.handle!r}',
  367. tag_mark,
  368. )
  369. if start_mark is None:
  370. start_mark = end_mark = self.scanner.peek_token().start_mark
  371. event = None
  372. implicit = tag is None or str(tag) == '!'
  373. if indentless_sequence and self.scanner.check_token(BlockEntryToken):
  374. comment = None
  375. pt = self.scanner.peek_token()
  376. if self.loader and self.loader.comment_handling is None:
  377. if pt.comment and pt.comment[0]:
  378. comment = [pt.comment[0], []]
  379. pt.comment[0] = None
  380. elif pt.comment and pt.comment[0] is None and pt.comment[1]:
  381. comment = [None, pt.comment[1]]
  382. pt.comment[1] = None
  383. elif self.loader:
  384. if pt.comment:
  385. comment = pt.comment
  386. end_mark = self.scanner.peek_token().end_mark
  387. event = SequenceStartEvent(
  388. anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
  389. )
  390. self.state = self.parse_indentless_sequence_entry
  391. return event
  392. if self.scanner.check_token(ScalarToken):
  393. token = self.scanner.get_token()
  394. # self.scanner.peek_token_same_line_comment(token)
  395. end_mark = token.end_mark
  396. if (token.plain and tag is None) or str(tag) == '!':
  397. dimplicit = (True, False)
  398. elif tag is None:
  399. dimplicit = (False, True)
  400. else:
  401. dimplicit = (False, False)
  402. event = ScalarEvent(
  403. anchor,
  404. tag,
  405. dimplicit,
  406. token.value,
  407. start_mark,
  408. end_mark,
  409. style=token.style,
  410. comment=token.comment,
  411. )
  412. self.state = self.states.pop()
  413. elif self.scanner.check_token(FlowSequenceStartToken):
  414. pt = self.scanner.peek_token()
  415. end_mark = pt.end_mark
  416. event = SequenceStartEvent(
  417. anchor,
  418. tag,
  419. implicit,
  420. start_mark,
  421. end_mark,
  422. flow_style=True,
  423. comment=pt.comment,
  424. )
  425. self.state = self.parse_flow_sequence_first_entry
  426. elif self.scanner.check_token(FlowMappingStartToken):
  427. pt = self.scanner.peek_token()
  428. end_mark = pt.end_mark
  429. event = MappingStartEvent(
  430. anchor,
  431. tag,
  432. implicit,
  433. start_mark,
  434. end_mark,
  435. flow_style=True,
  436. comment=pt.comment,
  437. )
  438. self.state = self.parse_flow_mapping_first_key
  439. elif block and self.scanner.check_token(BlockSequenceStartToken):
  440. end_mark = self.scanner.peek_token().start_mark
  441. # should inserting the comment be dependent on the
  442. # indentation?
  443. pt = self.scanner.peek_token()
  444. comment = pt.comment
  445. # nprint('pt0', type(pt))
  446. if comment is None or comment[1] is None:
  447. comment = pt.split_old_comment()
  448. # nprint('pt1', comment)
  449. event = SequenceStartEvent(
  450. anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
  451. )
  452. self.state = self.parse_block_sequence_first_entry
  453. elif block and self.scanner.check_token(BlockMappingStartToken):
  454. end_mark = self.scanner.peek_token().start_mark
  455. comment = self.scanner.peek_token().comment
  456. event = MappingStartEvent(
  457. anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
  458. )
  459. self.state = self.parse_block_mapping_first_key
  460. elif anchor is not None or tag is not None:
  461. # Empty scalars are allowed even if a tag or an anchor is
  462. # specified.
  463. event = ScalarEvent(anchor, tag, (implicit, False), "", start_mark, end_mark)
  464. self.state = self.states.pop()
  465. else:
  466. if block:
  467. node = 'block'
  468. else:
  469. node = 'flow'
  470. token = self.scanner.peek_token()
  471. raise ParserError(
  472. f'while parsing a {node!s} node',
  473. start_mark,
  474. f'expected the node content, but found {token.id!r}',
  475. token.start_mark,
  476. )
  477. return event
  478. # block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
  479. # BLOCK-END
  480. def parse_block_sequence_first_entry(self) -> Any:
  481. token = self.scanner.get_token()
  482. # move any comment from start token
  483. # self.move_token_comment(token)
  484. self.marks.append(token.start_mark)
  485. return self.parse_block_sequence_entry()
  486. def parse_block_sequence_entry(self) -> Any:
  487. if self.scanner.check_token(BlockEntryToken):
  488. token = self.scanner.get_token()
  489. self.move_token_comment(token)
  490. if not self.scanner.check_token(BlockEntryToken, BlockEndToken):
  491. self.states.append(self.parse_block_sequence_entry)
  492. return self.parse_block_node()
  493. else:
  494. self.state = self.parse_block_sequence_entry
  495. return self.process_empty_scalar(token.end_mark)
  496. if not self.scanner.check_token(BlockEndToken):
  497. token = self.scanner.peek_token()
  498. raise ParserError(
  499. 'while parsing a block collection',
  500. self.marks[-1],
  501. f'expected <block end>, but found {token.id!r}',
  502. token.start_mark,
  503. )
  504. token = self.scanner.get_token() # BlockEndToken
  505. event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)
  506. self.state = self.states.pop()
  507. self.marks.pop()
  508. return event
  509. # indentless_sequence ::= (BLOCK-ENTRY block_node?)+
  510. # indentless_sequence?
  511. # sequence:
  512. # - entry
  513. # - nested
  514. def parse_indentless_sequence_entry(self) -> Any:
  515. if self.scanner.check_token(BlockEntryToken):
  516. token = self.scanner.get_token()
  517. self.move_token_comment(token)
  518. if not self.scanner.check_token(
  519. BlockEntryToken, KeyToken, ValueToken, BlockEndToken,
  520. ):
  521. self.states.append(self.parse_indentless_sequence_entry)
  522. return self.parse_block_node()
  523. else:
  524. self.state = self.parse_indentless_sequence_entry
  525. return self.process_empty_scalar(token.end_mark)
  526. token = self.scanner.peek_token()
  527. c = None
  528. if self.loader and self.loader.comment_handling is None:
  529. c = token.comment
  530. start_mark = token.start_mark
  531. else:
  532. start_mark = self.last_event.end_mark # type: ignore
  533. c = self.distribute_comment(token.comment, start_mark.line) # type: ignore
  534. event = SequenceEndEvent(start_mark, start_mark, comment=c)
  535. self.state = self.states.pop()
  536. return event
  537. # block_mapping ::= BLOCK-MAPPING_START
  538. # ((KEY block_node_or_indentless_sequence?)?
  539. # (VALUE block_node_or_indentless_sequence?)?)*
  540. # BLOCK-END
  541. def parse_block_mapping_first_key(self) -> Any:
  542. token = self.scanner.get_token()
  543. self.marks.append(token.start_mark)
  544. return self.parse_block_mapping_key()
  545. def parse_block_mapping_key(self) -> Any:
  546. if self.scanner.check_token(KeyToken):
  547. token = self.scanner.get_token()
  548. self.move_token_comment(token)
  549. if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):
  550. self.states.append(self.parse_block_mapping_value)
  551. return self.parse_block_node_or_indentless_sequence()
  552. else:
  553. self.state = self.parse_block_mapping_value
  554. return self.process_empty_scalar(token.end_mark)
  555. if self.resolver.processing_version > (1, 1) and self.scanner.check_token(ValueToken):
  556. self.state = self.parse_block_mapping_value
  557. return self.process_empty_scalar(self.scanner.peek_token().start_mark)
  558. if not self.scanner.check_token(BlockEndToken):
  559. token = self.scanner.peek_token()
  560. raise ParserError(
  561. 'while parsing a block mapping',
  562. self.marks[-1],
  563. f'expected <block end>, but found {token.id!r}',
  564. token.start_mark,
  565. )
  566. token = self.scanner.get_token()
  567. self.move_token_comment(token)
  568. event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)
  569. self.state = self.states.pop()
  570. self.marks.pop()
  571. return event
  572. def parse_block_mapping_value(self) -> Any:
  573. if self.scanner.check_token(ValueToken):
  574. token = self.scanner.get_token()
  575. # value token might have post comment move it to e.g. block
  576. if self.scanner.check_token(ValueToken):
  577. self.move_token_comment(token)
  578. else:
  579. if not self.scanner.check_token(KeyToken):
  580. self.move_token_comment(token, empty=True)
  581. # else: empty value for this key cannot move token.comment
  582. if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):
  583. self.states.append(self.parse_block_mapping_key)
  584. return self.parse_block_node_or_indentless_sequence()
  585. else:
  586. self.state = self.parse_block_mapping_key
  587. comment = token.comment
  588. if comment is None:
  589. token = self.scanner.peek_token()
  590. comment = token.comment
  591. if comment:
  592. token._comment = [None, comment[1]]
  593. comment = [comment[0], None]
  594. return self.process_empty_scalar(token.end_mark, comment=comment)
  595. else:
  596. self.state = self.parse_block_mapping_key
  597. token = self.scanner.peek_token()
  598. return self.process_empty_scalar(token.start_mark)
  599. # flow_sequence ::= FLOW-SEQUENCE-START
  600. # (flow_sequence_entry FLOW-ENTRY)*
  601. # flow_sequence_entry?
  602. # FLOW-SEQUENCE-END
  603. # flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
  604. #
  605. # Note that while production rules for both flow_sequence_entry and
  606. # flow_mapping_entry are equal, their interpretations are different.
  607. # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
  608. # generate an inline mapping (set syntax).
  609. def parse_flow_sequence_first_entry(self) -> Any:
  610. token = self.scanner.get_token()
  611. self.marks.append(token.start_mark)
  612. return self.parse_flow_sequence_entry(first=True)
  613. def parse_flow_sequence_entry(self, first: bool = False) -> Any:
  614. if not self.scanner.check_token(FlowSequenceEndToken):
  615. if not first:
  616. if self.scanner.check_token(FlowEntryToken):
  617. self.scanner.get_token()
  618. else:
  619. token = self.scanner.peek_token()
  620. raise ParserError(
  621. 'while parsing a flow sequence',
  622. self.marks[-1],
  623. f"expected ',' or ']', but got {token.id!r}",
  624. token.start_mark,
  625. )
  626. if self.scanner.check_token(KeyToken):
  627. token = self.scanner.peek_token()
  628. event: Any = MappingStartEvent(
  629. None, None, True, token.start_mark, token.end_mark, flow_style=True,
  630. )
  631. self.state = self.parse_flow_sequence_entry_mapping_key
  632. return event
  633. elif not self.scanner.check_token(FlowSequenceEndToken):
  634. self.states.append(self.parse_flow_sequence_entry)
  635. return self.parse_flow_node()
  636. token = self.scanner.get_token()
  637. event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)
  638. self.state = self.states.pop()
  639. self.marks.pop()
  640. return event
  641. def parse_flow_sequence_entry_mapping_key(self) -> Any:
  642. token = self.scanner.get_token()
  643. if not self.scanner.check_token(ValueToken, FlowEntryToken, FlowSequenceEndToken):
  644. self.states.append(self.parse_flow_sequence_entry_mapping_value)
  645. return self.parse_flow_node()
  646. else:
  647. self.state = self.parse_flow_sequence_entry_mapping_value
  648. return self.process_empty_scalar(token.end_mark)
  649. def parse_flow_sequence_entry_mapping_value(self) -> Any:
  650. if self.scanner.check_token(ValueToken):
  651. token = self.scanner.get_token()
  652. if not self.scanner.check_token(FlowEntryToken, FlowSequenceEndToken):
  653. self.states.append(self.parse_flow_sequence_entry_mapping_end)
  654. return self.parse_flow_node()
  655. else:
  656. self.state = self.parse_flow_sequence_entry_mapping_end
  657. return self.process_empty_scalar(token.end_mark)
  658. else:
  659. self.state = self.parse_flow_sequence_entry_mapping_end
  660. token = self.scanner.peek_token()
  661. return self.process_empty_scalar(token.start_mark)
  662. def parse_flow_sequence_entry_mapping_end(self) -> Any:
  663. self.state = self.parse_flow_sequence_entry
  664. token = self.scanner.peek_token()
  665. return MappingEndEvent(token.start_mark, token.start_mark)
  666. # flow_mapping ::= FLOW-MAPPING-START
  667. # (flow_mapping_entry FLOW-ENTRY)*
  668. # flow_mapping_entry?
  669. # FLOW-MAPPING-END
  670. # flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
  671. def parse_flow_mapping_first_key(self) -> Any:
  672. token = self.scanner.get_token()
  673. self.marks.append(token.start_mark)
  674. return self.parse_flow_mapping_key(first=True)
  675. def parse_flow_mapping_key(self, first: Any = False) -> Any:
  676. if not self.scanner.check_token(FlowMappingEndToken):
  677. if not first:
  678. if self.scanner.check_token(FlowEntryToken):
  679. self.scanner.get_token()
  680. else:
  681. token = self.scanner.peek_token()
  682. raise ParserError(
  683. 'while parsing a flow mapping',
  684. self.marks[-1],
  685. f"expected ',' or '}}', but got {token.id!r}",
  686. token.start_mark,
  687. )
  688. if self.scanner.check_token(KeyToken):
  689. token = self.scanner.get_token()
  690. if not self.scanner.check_token(
  691. ValueToken, FlowEntryToken, FlowMappingEndToken,
  692. ):
  693. self.states.append(self.parse_flow_mapping_value)
  694. return self.parse_flow_node()
  695. else:
  696. self.state = self.parse_flow_mapping_value
  697. return self.process_empty_scalar(token.end_mark)
  698. elif self.resolver.processing_version > (1, 1) and self.scanner.check_token(
  699. ValueToken,
  700. ):
  701. self.state = self.parse_flow_mapping_value
  702. return self.process_empty_scalar(self.scanner.peek_token().end_mark)
  703. elif not self.scanner.check_token(FlowMappingEndToken):
  704. self.states.append(self.parse_flow_mapping_empty_value)
  705. return self.parse_flow_node()
  706. token = self.scanner.get_token()
  707. event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)
  708. self.state = self.states.pop()
  709. self.marks.pop()
  710. return event
  711. def parse_flow_mapping_value(self) -> Any:
  712. if self.scanner.check_token(ValueToken):
  713. token = self.scanner.get_token()
  714. if not self.scanner.check_token(FlowEntryToken, FlowMappingEndToken):
  715. self.states.append(self.parse_flow_mapping_key)
  716. return self.parse_flow_node()
  717. else:
  718. self.state = self.parse_flow_mapping_key
  719. return self.process_empty_scalar(token.end_mark)
  720. else:
  721. self.state = self.parse_flow_mapping_key
  722. token = self.scanner.peek_token()
  723. return self.process_empty_scalar(token.start_mark)
  724. def parse_flow_mapping_empty_value(self) -> Any:
  725. self.state = self.parse_flow_mapping_key
  726. return self.process_empty_scalar(self.scanner.peek_token().start_mark)
  727. def process_empty_scalar(self, mark: Any, comment: Any = None) -> Any:
  728. return ScalarEvent(None, None, (True, False), "", mark, mark, comment=comment)
  729. def move_token_comment(
  730. self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,
  731. ) -> Any:
  732. pass
  733. class RoundTripParser(Parser):
  734. """roundtrip is a safe loader, that wants to see the unmangled tag"""
  735. def select_tag_transform(self, tag: Tag) -> None:
  736. if tag is None:
  737. return
  738. tag.select_transform(True)
  739. def move_token_comment(
  740. self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,
  741. ) -> Any:
  742. token.move_old_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)
  743. class RoundTripParserSC(RoundTripParser):
  744. """roundtrip is a safe loader, that wants to see the unmangled tag"""
  745. # some of the differences are based on the superclass testing
  746. # if self.loader.comment_handling is not None
  747. def move_token_comment(
  748. self: Any, token: Any, nt: Any = None, empty: Optional[bool] = False,
  749. ) -> None:
  750. token.move_new_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)
  751. def distribute_comment(self, comment: Any, line: Any) -> Any:
  752. # ToDo, look at indentation of the comment to determine attachment
  753. if comment is None:
  754. return None
  755. if not comment[0]:
  756. return None
  757. # if comment[0][0] != line + 1:
  758. # nprintf('>>>dcxxx', comment, line)
  759. assert comment[0][0] == line + 1
  760. # if comment[0] - line > 1:
  761. # return
  762. typ = self.loader.comment_handling & 0b11
  763. # nprintf('>>>dca', comment, line, typ)
  764. if typ == C_POST:
  765. return None
  766. if typ == C_PRE:
  767. c = [None, None, comment[0]]
  768. comment[0] = None
  769. return c
  770. # nprintf('>>>dcb', comment[0])
  771. for _idx, cmntidx in enumerate(comment[0]):
  772. # nprintf('>>>dcb', cmntidx)
  773. if isinstance(self.scanner.comments[cmntidx], BlankLineComment):
  774. break
  775. else:
  776. return None # no space found
  777. if _idx == 0:
  778. return None # first line was blank
  779. # nprintf('>>>dcc', idx)
  780. if typ == C_SPLIT_ON_FIRST_BLANK:
  781. c = [None, None, comment[0][:_idx]]
  782. comment[0] = comment[0][_idx:]
  783. return c
  784. raise NotImplementedError # reserved