rapidyaml  0.16.0
parseandemitYAML,anddoitfast
event_handler_tree.hpp
Go to the documentation of this file.
1 #ifndef C4_YML_EVENT_HANDLER_TREE_HPP_
2 #define C4_YML_EVENT_HANDLER_TREE_HPP_
3 
4 #ifndef C4_YML_TREE_HPP_
5 #include "c4/yml/tree.hpp"
6 #endif
7 
8 #ifndef C4_YML_EVENT_HANDLER_STACK_HPP_
10 #endif
11 
12 C4_SUPPRESS_WARNING_GCC_PUSH
13 C4_SUPPRESS_WARNING_MSVC_PUSH
14 C4_SUPPRESS_WARNING_MSVC(4702) // unreachable code
15 #if defined(__GNUC__) && __GNUC__ >= 6
16 C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
17 #endif
18 
19 // NOLINTBEGIN(hicpp-signed-bitwise)
20 
21 namespace c4 {
22 namespace yml {
23 
24 /** @addtogroup doc_event_handlers_tree
25  *
26  * An event handler used by @ref ParseEngine to create the @ref Tree
27  * (see @ref Parser).
28  *
29  * @{ */
30 
31 
32 /** @cond dev */
33 struct EventHandlerTreeState : public ParserState
34 {
35  NodeData *tr_data;
36 };
37 /** @endcond */
38 
39 
40 /** The event handler to create a ryml @ref Tree. See the
41  * documentation for @ref doc_event_handlers, which has important
42  * notes about the event model used by rapidyaml. */
43 struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
44 {
45 
46  /** @name types
47  * @{ */
48 
49  using state = EventHandlerTreeState;
50  enum { requires_strings_on_buffers = false }; // NOLINT
51 
52  /** @} */
53 
54 public:
55 
56  /** @cond dev */
57  Tree *C4_RESTRICT m_tree;
58  id_type m_curr_doc;
59  TagCache m_tag_cache;
60 
61  #ifdef RYML_DBG
62  #define ryml_enable_(bits) enable_<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
63  #define ryml_disable_(bits) disable_<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
64  #else
65  #define ryml_enable_(bits) enable_<bits>()
66  #define ryml_disable_(bits) disable_<bits>()
67  #endif
68  #define ryml_hasany_(bits) has_any_<bits>()
69  /** @endcond */
70 
71 public:
72 
73  /** @name construction and resetting
74  * @{ */
75 
76  EventHandlerTree() noexcept : EventHandlerStack(), m_tree(), m_curr_doc() {}
77  EventHandlerTree(Callbacks const& cb) noexcept : EventHandlerStack(cb), m_tree(), m_curr_doc() {}
78  EventHandlerTree(Tree *tree, id_type id) /*except!*/ : EventHandlerStack(tree->callbacks()), m_tree(tree), m_curr_doc()
79  {
80  reset(tree, id);
81  }
82 
83  void reset(Tree *tree, id_type id)
84  {
85  if C4_UNLIKELY(!tree)
86  RYML_ERR_BASIC_CB_(m_stack.m_callbacks, "null tree");
87  if C4_UNLIKELY(id >= tree->capacity())
88  RYML_ERR_VISIT_CB_(tree->callbacks(), tree, id, "invalid node");
89  if C4_UNLIKELY(!tree->is_root(id))
90  if C4_UNLIKELY(tree->is_map(tree->parent(id)))
91  if C4_UNLIKELY(!tree->has_key(id))
92  RYML_ERR_BASIC_CB_(tree->callbacks(), "destination node belongs to a map and has no key");
93  m_tree = tree;
94  if(m_tree->is_root(id))
95  {
97  _reset_parser_state(m_curr, id, m_tree->root_id());
98  }
99  else
100  {
102  _reset_parser_state(m_parent, id, m_tree->parent(id));
103  _reset_parser_state(m_curr, id, id);
104  }
105  m_curr_doc = m_tree->ancestor_doc(id);
106  m_tag_cache.clear();
107  }
108 
109  Callbacks const& callbacks() const { return m_stack.m_callbacks; }
110 
111  C4_ALWAYS_INLINE TagDirectives& tag_directives() { return m_tree->m_tag_directives; } // NOLINT(readability-make-member-function-const)
112  C4_ALWAYS_INLINE TagCache &tag_cache() { return m_tag_cache; }
113 
114  /** @} */
115 
116 public:
117 
118  /** @name parse events
119  * @{ */
120 
121  void start_parse(const char* filename, substr ymlsrc)
122  {
123  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree != nullptr);
124  this->_stack_start_parse(filename, ymlsrc);
125  }
126 
128  {
129  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree != nullptr);
130  this->_stack_finish_parse();
131  /* This pointer is temporary. Remember that:
132  *
133  * - this handler object may be held by the user
134  * - it may be used with a temporary tree inside the parse function
135  * - when the parse function returns the temporary tree, its address
136  * will change
137  *
138  * As a result, the user could try to read the tree from m_tree, and
139  * end up reading the stale temporary object.
140  *
141  * So it is better to clear it here; then the user will get an obvious
142  * segfault if reading from m_tree. */
143  m_tree = nullptr;
144  }
145 
147  {
148  m_tree = nullptr;
149  }
150 
151  /** @} */
152 
153 public:
154 
155  /** @name YAML stream events */
156  /** @{ */
157 
158  C4_ALWAYS_INLINE void begin_stream() const noexcept { /* nothing to do */ }
159 
160  C4_ALWAYS_INLINE void end_stream() const noexcept { /* nothing to do */ }
161 
162  /** @} */
163 
164 public:
165 
166  /** @name YAML document events */
167  /** @{ */
168 
169  /** implicit doc start (without ---) */
170  void begin_doc()
171  {
172  _c4dbgp("begin_doc");
174  {
175  _c4dbgp("push!");
176  _set_root_as_stream();
177  _push();
178  ryml_enable_(DOC);
179  }
180  m_curr_doc = m_curr->node_id;
181  }
182  /** implicit doc end (without ...) */
183  void end_doc()
184  {
185  _c4dbgp("end_doc");
186  m_curr_doc = m_tree->size();
188  {
189  _remove_speculative();
190  _c4dbgp("pop!");
191  _pop();
192  }
193  }
194 
195  /** explicit doc start, with --- */
197  {
198  _c4dbgp("begin_doc_expl");
199  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id, m_tree, m_curr->node_id);
200  if(m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
201  {
202  _c4dbgp("push!");
203  _push();
204  }
205  else
206  {
207  _c4dbgp("ensure stream");
208  _set_root_as_stream();
209  const id_type root = m_tree->root_id();
210  const id_type first = m_tree->first_child(root);
211  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->is_stream(root), m_tree, root);
212  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->num_children(root) == 1u, m_tree, root);
213  if(m_tree->is_container(first) || m_tree->is_val(first))
214  {
215  _c4dbgp("push!");
216  _push();
217  #ifdef RYML_WITH_COMMENTS
218  m_tree->_p(root)->m_first_comment = NONE;
219  m_tree->_p(root)->m_last_comment = NONE;
220  #endif
221  }
222  else
223  {
224  _c4dbgp("tweak");
225  _push();
226  _remove_speculative();
227  m_curr->node_id = m_tree->last_child(root);
228  m_curr->tr_data = m_tree->_p(m_curr->node_id);
229  }
230  }
231  ryml_enable_(DOC);
232  m_curr_doc = m_curr->node_id;
233  }
234  /** explicit doc end, with ... */
236  {
237  _c4dbgp("end_doc_expl");
238  m_curr_doc = m_tree->size();
239  _remove_speculative();
241  {
242  _c4dbgp("pop!");
243  _pop();
244  }
245  }
246 
247  /** @} */
248 
249 public:
250 
251  /** @name YAML map events */
252  /** @{ */
253 
254  C4_NORETURN void begin_map_key_flow()
255  {
256  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
257  }
258  C4_NORETURN void begin_map_key_block()
259  {
260  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
261  }
262 
264  {
265  _c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
266  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
267  ryml_enable_(MAP|FLOW_SL);
268  _save_loc();
269  _push();
270  }
272  {
273  _c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
274  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
275  ryml_enable_(MAP|BLOCK);
276  _save_loc();
277  _push();
278  }
279 
281  {
282  _c4dbgpf("node[{}]: end_map_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
283  _pop();
284  }
285 
286  void end_map_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
287  {
288  _c4dbgpf("node[{}]: end_map. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
289  _pop();
290  if(multiline)
291  {
292  ryml_disable_(FLOW_SL);
293  enable_(multiline_style);
294  }
295  }
296 
297  /** @} */
298 
299 public:
300 
301  /** @name YAML seq events */
302  /** @{ */
303 
304  C4_NORETURN void begin_seq_key_flow()
305  {
306  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
307  }
308  C4_NORETURN void begin_seq_key_block()
309  {
310  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
311  }
312 
314  {
315  _c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
316  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
317  ryml_enable_(SEQ|FLOW_SL);
318  _save_loc();
319  _push();
320  }
322  {
323  _c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
324  RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
325  ryml_enable_(SEQ|BLOCK);
326  _save_loc();
327  _push();
328  }
329 
331  {
332  _c4dbgpf("node[{}]: end_seq_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
333  _pop();
334  }
335 
336  void end_seq_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
337  {
338  _c4dbgpf("node[{}]: end_seq. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
339  _pop();
340  if(multiline)
341  {
342  ryml_disable_(FLOW_SL);
343  enable_(multiline_style);
344  }
345  }
346 
347  /** @} */
348 
349 public:
350 
351  /** @name YAML structure events */
352  /** @{ */
353 
354  void add_sibling()
355  {
356  #if defined(__GNUC__) && (__GNUC__ >= 6)
357  C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
358  #endif
359  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
360  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
361  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id), m_tree, m_parent->node_id);
362  NodeData const* const prev = m_tree->m_buf; // watchout against relocation of the tree nodes
363  _set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
364  if(prev != m_tree->m_buf)
365  _refresh_after_relocation();
366  _c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
367  #if defined(__GNUC__) && (__GNUC__ >= 6)
368  C4_SUPPRESS_WARNING_GCC_POP
369  #endif
370  }
371 
372  /** reset the previous val as the first key of a new map, with flow style.
373  *
374  * See the documentation for @ref doc_event_handlers, which has
375  * important notes about this event.
376  */
378  {
379  if C4_UNLIKELY(m_tree->is_container(m_curr->node_id))
380  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
381  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
382  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id), m_tree, m_parent->node_id);
383  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id), m_tree, m_curr->node_id);
384  RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id), m_tree, m_curr->node_id);
385  const NodeData tmp = _val2key_(*m_curr->tr_data);
386  ryml_disable_(VALMASK_|VAL_STYLE|VALNIL);
387  m_curr->tr_data->m_val = {};
389  m_curr->tr_data->m_type = tmp.m_type;
390  m_curr->tr_data->m_key = tmp.m_key;
391  }
392 
393  /** like its flow counterpart, but this function can only be
394  * called after the end of a flow-val at root or doc level.
395  *
396  * See the documentation for @ref doc_event_handlers, which has
397  * important notes about this event.
398  */
400  {
401  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
402  }
403 
404  /** @} */
405 
406 public:
407 
408  /** @name YAML scalar events */
409  /** @{ */
410 
411 
412  C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
413  {
414  _c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
415  m_curr->tr_data->m_key.scalar = {};
416  ryml_enable_(KEY|KEY_PLAIN|KEYNIL);
417  }
418  C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
419  {
420  _c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
421  m_curr->tr_data->m_val.scalar = {};
422  ryml_enable_(VAL|VAL_PLAIN|VALNIL);
423  }
424 
425  C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
426  {
427  _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
428  m_curr->tr_data->m_key.scalar = scalar;
429  ryml_enable_(KEY|KEY_PLAIN);
430  }
431  C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
432  {
433  _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
434  m_curr->tr_data->m_val.scalar = scalar;
435  ryml_enable_(VAL|VAL_PLAIN);
436  }
437 
438 
439  C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
440  {
441  _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
442  m_curr->tr_data->m_key.scalar = scalar;
443  ryml_enable_(KEY|KEY_DQUO);
444  }
445  C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
446  {
447  _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
448  m_curr->tr_data->m_val.scalar = scalar;
449  ryml_enable_(VAL|VAL_DQUO);
450  }
451 
452 
453  C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
454  {
455  _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
456  m_curr->tr_data->m_key.scalar = scalar;
457  ryml_enable_(KEY|KEY_SQUO);
458  }
459  C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
460  {
461  _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
462  m_curr->tr_data->m_val.scalar = scalar;
463  ryml_enable_(VAL|VAL_SQUO);
464  }
465 
466 
467  C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
468  {
469  _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
470  m_curr->tr_data->m_key.scalar = scalar;
471  ryml_enable_(KEY|KEY_LITERAL);
472  }
473  C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
474  {
475  _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
476  m_curr->tr_data->m_val.scalar = scalar;
477  ryml_enable_(VAL|VAL_LITERAL);
478  }
479 
480 
481  C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
482  {
483  _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
484  m_curr->tr_data->m_key.scalar = scalar;
485  ryml_enable_(KEY|KEY_FOLDED);
486  }
487  C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
488  {
489  _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
490  m_curr->tr_data->m_val.scalar = scalar;
491  ryml_enable_(VAL|VAL_FOLDED);
492  }
493 
494 
495  C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
496  {
497  ryml_enable_(KEY_UNFILT);
498  }
499  C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
500  {
501  ryml_enable_(VAL_UNFILT);
502  }
503 
504  /** @} */
505 
506 public:
507 
508  /** @name YAML anchor/reference events */
509  /** @{ */
510 
511  void set_key_anchor(csubstr anchor)
512  {
513  _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
514  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
515  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(KEYREF));
516  RYML_ASSERT_PARSE_CB_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
517  ryml_enable_(KEYANCH);
518  m_curr->tr_data->m_key.anchor = anchor;
519  }
520  void set_val_anchor(csubstr anchor)
521  {
522  _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
523  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
524  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VALREF));
525  RYML_ASSERT_PARSE_CB_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
526  ryml_enable_(VALANCH);
527  m_curr->tr_data->m_val.anchor = anchor;
528  }
529 
531  {
532  _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
533  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
534  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_hasany_(KEYANCH), m_curr->pos);
535  ryml_enable_(KEY|KEYREF);
536  m_curr->tr_data->m_key.anchor = ref.sub(1);
537  m_curr->tr_data->m_key.scalar = ref;
538  }
540  {
541  _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
542  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
543  RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_hasany_(VALANCH), m_curr->pos);
544  ryml_enable_(VAL|VALREF);
545  m_curr->tr_data->m_val.anchor = ref.sub(1);
546  m_curr->tr_data->m_val.scalar = ref;
547  }
548 
549  /** @} */
550 
551 public:
552 
553  /** @name YAML tag events */
554  /** @{ */
555 
557  {
558  _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
559  ryml_enable_(KEYTAG);
560  m_curr->tr_data->m_key.tag = tag;
561  }
563  {
564  _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
565  ryml_enable_(VALTAG);
566  m_curr->tr_data->m_val.tag = tag;
567  }
568 
569  /** @} */
570 
571 public:
572 
573  /** @name YAML directive events */
574  /** @{ */
575 
576  void add_directive_yaml(csubstr yaml_version) // NOLINT(readability-convert-member-functions-to-static)
577  {
578  _c4dbgpf("%YAML directive! version={}", yaml_version);
579  (void)yaml_version;
580  }
581 
582  void add_directive_tag(csubstr handle, csubstr prefix)
583  {
584  _c4dbgpf("%TAG directive! handle={} prefix={} id={}", handle, prefix, m_curr_doc);
585  if C4_UNLIKELY(!m_tree->m_tag_directives.add(handle, prefix, m_curr_doc))
586  RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "too many %TAG directives");
587  }
588 
589  /** @} */
590 
591 public:
592 
593  /** @name arena functions */
594  /** @{ */
595 
597  {
598  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
599  return m_tree->m_arena.first(m_tree->m_arena_pos);
600  }
602  {
603  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
604  return m_tree->m_arena.sub(m_tree->m_arena_pos);
605  }
606  substr alloc_arena(size_t len) // NOLINT(readability-make-member-function-const)
607  {
608  return m_tree->alloc_arena(len);
609  }
610 
611  /** @} */
612 
613 public:
614 
615  /** @cond dev */
616  void _reset_parser_state(state* st, id_type parse_root, id_type node)
617  {
618  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
619  _set_state_(st, node);
620  const NodeType type = m_tree->type(node);
621  #ifdef RYML_DBG
622  char flagbuf[80];
623  _c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
624  #endif
625  if(type == NOTYPE)
626  {
627  _c4dbgpf("node[{}] is notype", node);
628  if(m_tree->is_root(parse_root))
629  {
630  _c4dbgpf("node[{}] is root", node);
631  st->flags |= RUNK|RTOP;
632  }
633  else
634  {
635  _c4dbgpf("node[{}] is not root. setting USTY", node);
636  st->flags |= USTY;
637  }
638  }
639  else if(type.is_map())
640  {
641  _c4dbgpf("node[{}] is map", node);
642  st->flags |= RMAP|USTY;
643  }
644  else if(type.is_seq())
645  {
646  _c4dbgpf("node[{}] is map", node);
647  st->flags |= RSEQ|USTY;
648  }
649  else if(type.has_key())
650  {
651  _c4dbgpf("node[{}] has key. setting USTY", node);
652  st->flags |= USTY;
653  }
654  else
655  {
656  RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree, node, "cannot append to node"); // LCOV_EXCL_LINE
657  }
658  if(type.is_doc())
659  {
660  _c4dbgpf("node[{}] is doc", node);
661  st->flags |= RDOC;
662  }
663  #ifdef RYML_DBG
664  _c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
665  #endif
666  }
667 
668  /** push a new parent, add a child to the new parent, and set the
669  * child as the current node */
670  void _push()
671  {
672  _stack_push();
673  NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
674  m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
675  m_curr->tr_data = m_tree->_p(m_curr->node_id);
676  if(prev != m_tree->m_buf)
677  _refresh_after_relocation();
678  _c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
679  }
680  /** end the current scope */
681  void _pop()
682  {
683  _remove_speculative_with_parent();
684  _stack_pop();
685  }
686 
687 public:
688 
689  C4_ALWAYS_INLINE void enable_(type_bits bits) noexcept
690  {
691  m_curr->tr_data->m_type.m_bits |= bits;
692  }
693  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void enable_() noexcept
694  {
695  m_curr->tr_data->m_type.m_bits |= bits;
696  }
697  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void disable_() noexcept
698  {
699  m_curr->tr_data->m_type.m_bits &= ~bits;
700  }
701  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool has_any_() const noexcept
702  {
703  return (m_curr->tr_data->m_type.m_bits & bits) != 0;
704  }
705 
706 public:
707 
708  C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
709  {
710  s->node_id = id;
711  s->tr_data = m_tree->_p(id);
712  }
713  void _refresh_after_relocation()
714  {
715  _c4dbgp("tree: refreshing stack data after tree data relocation");
716  for(auto &st : m_stack)
717  st.tr_data = m_tree->_p(st.node_id);
718  }
719 
720  void _set_root_as_stream()
721  {
722  _c4dbgp("set root as stream");
723  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->root_id() == 0u, m_tree, m_tree->root_id());
724  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_curr->node_id == 0u, m_tree, m_curr->node_id);
725  m_tree->set_root_as_stream();
726  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()), m_tree, m_tree->root_id());
727  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()), m_tree, m_tree->root_id());
728  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())), m_tree, m_tree->root_id());
729  _set_state_(m_curr, m_tree->root_id());
730  }
731 
732  static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
733  {
734  NodeData r = d;
735  r.m_key = d.m_val;
736  r.m_val = {};
737  r.m_type = d.m_type;
738  static_assert((VALMASK_ >> 1u) == KEYMASK_, "required for this function to work");
739  static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
740  r.m_type.m_bits = ((d.m_type.m_bits & (VALMASK_|VAL_STYLE)) >> 1u);
741  r.m_type.m_bits = (r.m_type.m_bits & ~(VALMASK_|VAL_STYLE));
742  r.m_type.m_bits = (r.m_type.m_bits | KEY);
743  if(d.m_type.m_bits & VALNIL)
744  r.m_type.m_bits = (r.m_type.m_bits | KEYNIL);
745  return r;
746  }
747 
748  void _remove_speculative()
749  {
750  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
751  RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), !m_tree->empty());
752  const id_type last_added = m_tree->size() - 1;
753  const NodeData *C4_RESTRICT d = m_tree->_p(last_added);
754  if(d->m_parent != NONE && d->m_type == NOTYPE)
755  {
756  _c4dbgpf("remove speculative: currparent={} node={} parent(node)={}", m_parent->node_id, last_added, d->m_parent);
757  m_tree->remove(last_added);
758  --m_curr->node_id;
759  }
760  }
761 
762  void _remove_speculative_with_parent()
763  {
764  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
765  RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), !m_tree->empty());
766  const id_type last_added = m_tree->size() - 1;
767  RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->has_parent(last_added), m_tree, last_added);
768  if(m_tree->_p(last_added)->m_type == NOTYPE)
769  {
770  _c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
771  m_tree->remove(last_added);
772  --m_curr->node_id;
773  }
774  }
775 
776  C4_ALWAYS_INLINE void _save_loc()
777  {
778  RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
779  RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
780  m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
781  }
782 
783 #undef ryml_enable_
784 #undef ryml_disable_
785 #undef ryml_has_any_
786 
787  /** @endcond */
788 };
789 
790 /** @} */
791 
792 } // namespace yml
793 } // namespace c4
794 
795 // NOLINTEND(hicpp-signed-bitwise)
796 C4_SUPPRESS_WARNING_MSVC_POP
797 C4_SUPPRESS_WARNING_GCC_POP
798 
799 #endif /* C4_YML_EVENT_HANDLER_TREE_HPP_ */
void begin_doc_expl()
explicit doc start, with —
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:156
void begin_doc()
implicit doc start (without —)
the val has an &anchor
Definition: node_type.hpp:42
the key has a tag
Definition: node_type.hpp:43
void end_doc()
implicit doc end (without ...)
an index to none
Definition: common.hpp:131
the val scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:52
reading unknown state (when starting): must determine whether scalar, map or seq
mark key scalar as double quoted "
Definition: node_type.hpp:153
void end_stream() const noexcept
bool is_doc() const noexcept
Definition: node_type.hpp:292
id_type capacity() const
Definition: tree.hpp:346
mark key scalar as multiline, block literal |
Definition: node_type.hpp:147
void reset(Tree *tree, id_type id)
mark val scalar as single quoted '
Definition: node_type.hpp:152
reading in unknown style mode - must determine FLOW or BLCK reading an implicit map nested in an expl...
EventHandlerTreeState state
the key scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:51
void start_parse(const char *filename, substr ymlsrc)
void mark_val_scalar_unfiltered() noexcept
contains the data for each YAML node.
Definition: tree.hpp:287
The event handler to create a ryml Tree.
id_type parent(id_type node) const
Definition: tree.hpp:569
void set_val_scalar_dquoted(csubstr scalar) noexcept
Use this class a base of implementations of event handler to simplify the stack logic.
void set_key_scalar_dquoted(csubstr scalar) noexcept
type_bits bits
Definition: node_type.cpp:70
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:373
the val has a tag
Definition: node_type.hpp:44
void set_val_scalar_plain(csubstr scalar) noexcept
mark val scalar as double quoted "
Definition: node_type.hpp:154
bool is_map() const noexcept
Definition: node_type.hpp:294
bool is_map(id_type node) const
Definition: tree.hpp:480
void actually_val_is_first_key_of_new_map_block()
like its flow counterpart, but this function can only be called after the end of a flow-val at root o...
void set_val_scalar_squoted(csubstr scalar) noexcept
reading a document
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags...
Definition: tag.hpp:70
void end_seq_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
a document
Definition: node_type.hpp:37
the key is null (eg { : b} results in a null key)
Definition: node_type.hpp:45
void set_key_scalar_folded(csubstr scalar) noexcept
bool has_key(id_type node) const
Definition: tree.hpp:482
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:34
void set_key_anchor(csubstr anchor)
the key has an &anchor
Definition: node_type.hpp:41
bool is_seq() const noexcept
Definition: node_type.hpp:295
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition: common.hpp:124
void end_map_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
mark val scalar as multiline, block folded >
Definition: node_type.hpp:150
void set_val_anchor(csubstr anchor)
void set_key_scalar_plain_empty() noexcept
mark key scalar as multiline, block folded >
Definition: node_type.hpp:149
void set_val_scalar_folded(csubstr scalar) noexcept
void clear() noexcept
Definition: tag.hpp:93
EventHandlerTree(Callbacks const &cb) noexcept
basic_substring sub(size_t first) const noexcept
return [first,len[
Definition: substr.hpp:502
Callbacks const & callbacks() const
Definition: tree.hpp:349
reading a seq
void set_key_scalar_plain(csubstr scalar) noexcept
void mark_key_scalar_unfiltered() noexcept
void add_directive_yaml(csubstr yaml_version)
the val is null (eg {a : } results in a null val)
Definition: node_type.hpp:46
a *reference: the val references an &anchor
Definition: node_type.hpp:40
mark container with block style < - seqs as <
Definition: node_type.hpp:136
the scalar to the left of : in a map's member
Definition: node_type.hpp:33
reading a map
a *reference: the key references an &anchor
Definition: node_type.hpp:39
void set_val_scalar_plain_empty() noexcept
reading at top level
mask of KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!) ...
Definition: node_type.hpp:176
no node type or style is set
Definition: node_type.hpp:32
void set_key_scalar_literal(csubstr scalar) noexcept
size_t len
the length of the substring
Definition: substr.hpp:218
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:155
bool has_key() const noexcept
Definition: node_type.hpp:296
EventHandlerTree(Tree *tree, id_type id)
Callbacks const & callbacks() const
void set_key_scalar_squoted(csubstr scalar) noexcept
mark val scalar as multiline, block literal |
Definition: node_type.hpp:148
void actually_val_is_first_key_of_new_map_flow()
reset the previous val as the first key of a new map, with flow style.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition: node_type.hpp:26
void begin_stream() const noexcept
bool is_root(id_type node) const
Definition: tree.hpp:529
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:35
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
Definition: node_type.hpp:213
mark key scalar as single quoted '
Definition: node_type.hpp:151
bool begins_with(const C c) const noexcept
true if the first character of the string is c
Definition: substr.hpp:850
mark container with multi-line flow style, 1 element per line < - seqs as <
Definition: node_type.hpp:75
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!) ...
Definition: node_type.hpp:177
void add_directive_tag(csubstr handle, csubstr prefix)
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:36
void set_val_scalar_literal(csubstr scalar) noexcept
state * m_curr
current stack level: top of the stack. cached here for easier access.
mark container with single-line flow style < - seqs as <
Definition: node_type.hpp:56
void end_doc_expl()
explicit doc end, with ...