rapidyaml  0.11.1
parse and emit YAML, and do it fast
event_handler_stack.hpp
Go to the documentation of this file.
1 #ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
2 #define _C4_YML_EVENT_HANDLER_STACK_HPP_
3 
4 #ifndef _C4_YML_DETAIL_STACK_HPP_
5 #include "c4/yml/detail/stack.hpp"
6 #endif
7 
8 #ifndef _C4_YML_NODE_TYPE_HPP_
9 #include "c4/yml/node_type.hpp"
10 #endif
11 
12 #ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
13 #include "c4/yml/detail/dbgprint.hpp"
14 #endif
15 
16 #ifndef _C4_YML_PARSER_STATE_HPP_
17 #include "c4/yml/parser_state.hpp"
18 #endif
19 
20 #ifdef RYML_DBG
21 #ifndef _C4_YML_DETAIL_PRINT_HPP_
22 #include "c4/yml/detail/print.hpp"
23 #endif
24 #endif
25 
26 // NOLINTBEGIN(hicpp-signed-bitwise)
27 
28 namespace c4 {
29 namespace yml {
30 
31 /** @addtogroup doc_event_handlers
32  * @{ */
33 
34 namespace detail {
35 using pfn_relocate_arena = void (*)(void*, csubstr prev_arena, substr next_arena);
36 } // detail
37 
38 /** Use this class a base of implementations of event handler to
39  * simplify the stack logic. */
40 template<class HandlerImpl, class HandlerState>
42 {
43  static_assert(std::is_base_of<ParserState, HandlerState>::value,
44  "ParserState must be a base of HandlerState");
45 
46  using state = HandlerState;
48 
49 public:
50 
51  detail::stack<state> m_stack;
52  state *C4_RESTRICT m_curr; ///< current stack level: top of the stack. cached here for easier access.
53  state *C4_RESTRICT m_parent; ///< parent of the current stack level.
54  pfn_relocate_arena m_relocate_arena; ///< callback when the arena gets relocated
56  csubstr m_src;
57 
58 protected:
59 
62 
63 protected:
64 
65  void _stack_start_parse(const char *filename, csubstr ymlsrc, pfn_relocate_arena relocate_arena, void *relocate_arena_data)
66  {
67  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_curr != nullptr);
68  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, relocate_arena != nullptr);
69  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, relocate_arena_data != nullptr);
70  m_curr->start_parse(filename, m_curr->node_id);
71  m_relocate_arena = relocate_arena;
72  m_relocate_arena_data = relocate_arena_data;
73  m_src = ymlsrc;
74  }
75 
77  {
78  m_src = {};
79  }
80 
81 protected:
82 
84  {
85  m_stack.clear();
86  m_stack.push({});
87  m_parent = nullptr;
88  m_curr = &m_stack.top();
89  }
90 
92  {
93  m_stack.clear();
94  m_stack.push({}); // parent
95  m_stack.push({}); // node
96  m_parent = &m_stack.top(1);
97  m_curr = &m_stack.top();
98  }
99 
100  void _stack_push()
101  {
102  m_stack.push_top();
103  m_parent = &m_stack.top(1); // don't use m_curr. watch out for relocations inside the prev push
104  m_curr = &m_stack.top();
105  m_curr->reset_after_push();
106  }
107 
108  void _stack_pop()
109  {
110  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
111  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_stack.size() > 1);
112  m_parent->reset_before_pop(*m_curr);
113  m_stack.pop();
114  m_parent = m_stack.size() > 1 ? &m_stack.top(1) : nullptr;
115  m_curr = &m_stack.top();
116  #ifdef RYML_DBG
117  if(m_parent)
118  _c4dbgpf("popped! top is now node={} (parent={})", m_curr->node_id, m_parent->node_id);
119  else
120  _c4dbgpf("popped! top is now node={} @ ROOT", m_curr->node_id);
121  #endif
122  }
123 
124 protected:
125 
126  // undefined at the end
127  #define _has_any_(bits) (static_cast<HandlerImpl const* C4_RESTRICT>(this)->template _has_any__<bits>())
128 
130  {
131  const bool is_root = (m_stack.size() == 1u);
132  return is_root && (_has_any_(DOC|VAL|MAP|SEQ) || m_curr->has_children);
133  }
134 
136  {
137  const bool is_root = (m_stack.size() == 1u);
138  return !is_root && _has_any_(DOC);
139  }
140 
141 protected:
142 
143  void _stack_relocate_to_new_arena(csubstr prev, substr curr)
144  {
145  for(state &st : m_stack)
146  {
147  if(st.line_contents.rem.is_sub(prev))
148  st.line_contents.rem = _stack_relocate_to_new_arena(st.line_contents.rem, prev, curr);
149  if(st.line_contents.full.is_sub(prev))
150  st.line_contents.full = _stack_relocate_to_new_arena(st.line_contents.full, prev, curr);
151  }
152  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_relocate_arena != nullptr);
153  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_relocate_arena_data != nullptr);
155  }
156 
157  substr _stack_relocate_to_new_arena(csubstr s, csubstr prev, substr curr)
158  {
159  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, prev.is_super(s));
160  auto pos = s.str - prev.str;
161  substr out = {curr.str + pos, s.len};
162  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, curr.is_super(out));
163  return out;
164  }
165 
166 public:
167 
168  /** Check whether the current parse tokens are trailing on the
169  * previous doc, and raise an error if they are. This function is
170  * called by the parse engine (not the event handler) before a doc
171  * is started. */
173  {
174  const bool is_root = (m_stack.size() == 1u);
175  const bool isndoc = (m_curr->flags & NDOC) != 0;
176  const bool suspicious = _has_any_(MAP|SEQ|VAL);
177  _c4dbgpf("target={} isroot={} suspicious={} ndoc={}", m_curr->node_id, is_root, suspicious, isndoc);
178  if((is_root || _has_any_(DOC)) && suspicious && !isndoc)
179  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "parse error");
180  }
181 
182 protected:
183 
184  #undef _has_any_
185 
186 };
187 
188 /** @} */
189 
190 } // namespace yml
191 } // namespace c4
192 
193 // NOLINTEND(hicpp-signed-bitwise)
194 
195 #endif /* _C4_YML_EVENT_HANDLER_STACK_HPP_ */
#define _has_any_(bits)
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:38
@ VAL
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:37
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:39
@ DOC
a document
Definition: node_type.hpp:40
void(*)(void *, csubstr prev_arena, substr next_arena) pfn_relocate_arena
@ NDOC
no document mode. a document has ended and another has not started yet.
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:511
Use this class a base of implementations of event handler to simplify the stack logic.
substr _stack_relocate_to_new_arena(csubstr s, csubstr prev, substr curr)
state * m_curr
current stack level: top of the stack. cached here for easier access.
void _stack_start_parse(const char *filename, csubstr ymlsrc, pfn_relocate_arena relocate_arena, void *relocate_arena_data)
pfn_relocate_arena m_relocate_arena
callback when the arena gets relocated
EventHandlerStack(Callbacks const &cb)
void check_trailing_doc_token() const
Check whether the current parse tokens are trailing on the previous doc, and raise an error if they a...
detail::stack< state > m_stack
void _stack_relocate_to_new_arena(csubstr prev, substr curr)
state * m_parent
parent of the current stack level.
detail::pfn_relocate_arena pfn_relocate_arena