3 #include "c4/yml/detail/dbgprint.hpp"
5 #include "c4/yml/detail/print.hpp"
7 #define _c4dbg_tree(...)
8 #define _c4dbg_node(...)
19 c += m_tree->has_key_anchor(n);
20 c += m_tree->has_val_anchor(n);
21 c += m_tree->is_key_ref(n);
22 c += m_tree->is_val_ref(n);
23 c += m_tree->has_key(n) && m_tree->key(n) ==
"<<";
24 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
25 c += count_anchors_and_refs_(ch);
29 void ReferenceResolver::gather_anchors_and_refs__(
id_type n)
32 if(m_tree->has_key(n))
34 if(!m_tree->is_key_quoted(n) && m_tree->key(n) ==
"<<")
36 _c4dbgpf(
"node[{}]: key is <<", n);
37 if(m_tree->has_val(n))
39 if(m_tree->is_val_ref(n))
41 _c4dbgpf(
"node[{}]: instance[{}]: val ref, inheriting! '{}'", n, m_refs.size(), m_tree->val_ref(n));
47 _c4dbgpf(
"node[{}]: not ref!", n);
50 else if(m_tree->is_seq(n))
54 _c4dbgpf(
"node[{}]: is seq!", n);
55 for(
id_type ich = m_tree->first_child(n); ich !=
NONE; ich = m_tree->next_sibling(ich))
57 _c4dbgpf(
"node[{}]: instance [{}]: val ref, inheriting multiple: {} '{}'", n, m_refs.size(), ich, m_tree->val_ref(ich));
58 if(C4_UNLIKELY(m_tree->is_container(ich)))
59 _RYML_ERR_VISIT_(m_tree->m_callbacks, m_tree, n,
"child={}: refs for << cannot be containers.", ich);
60 m_refs.push({
VALREF, ich,
NONE,
NONE, n, m_tree->next_sibling(n)});
66 _RYML_ERR_VISIT_(m_tree->m_callbacks, m_tree, n,
"refs for << must be either val or seq");
69 else if(m_tree->is_key_ref(n))
71 _c4dbgpf(
"node[{}]: instance[{}]: key ref: '{}', key='{}'", n, m_refs.size(), m_tree->key_ref(n), m_tree->has_key(n) ? m_tree->key(n) : csubstr{
"-"});
72 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->key(n) !=
"<<", m_tree, n);
73 _RYML_CHECK_VISIT_(m_tree->m_callbacks, (!m_tree->has_key(n)) || m_tree->key(n).ends_with(m_tree->key_ref(n)), m_tree, n);
78 if(m_tree->is_val_ref(n) && (!m_tree->has_key(n) || m_tree->key(n) !=
"<<"))
80 _c4dbgpf(
"node[{}]: instance[{}]: val ref: '{}'", n, m_refs.size(), m_tree->val_ref(n));
81 _RYML_CHECK_VISIT((!m_tree->has_val(n)) || m_tree->val(n).ends_with(m_tree->val_ref(n)), m_tree, n);
85 if(m_tree->has_key_anchor(n))
87 _c4dbgpf(
"node[{}]: instance[{}]: key anchor: '{}'", n, m_refs.size(), m_tree->key_anchor(n));
88 _RYML_CHECK_VISIT(m_tree->has_key(n), m_tree, n);
91 if(m_tree->has_val_anchor(n))
93 _c4dbgpf(
"node[{}]: instance[{}]: val anchor: '{}'", n, m_refs.size(), m_tree->val_anchor(n));
94 _RYML_CHECK_VISIT(m_tree->has_val(n) || m_tree->is_container(n), m_tree, n);
98 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
99 gather_anchors_and_refs__(ch);
102 void ReferenceResolver::gather_anchors_and_refs_()
104 _c4dbgp(
"gathering anchors and refs...");
107 id_type num_anchors_and_refs = count_anchors_and_refs_(m_tree->root_id());
108 if(!num_anchors_and_refs)
110 m_refs.reserve(num_anchors_and_refs);
114 gather_anchors_and_refs__(m_tree->root_id());
116 _c4dbgpf(
"found {} anchors/refs", m_refs.size());
121 for(
auto &rd : m_refs)
123 rd.prev_anchor = prev_anchor;
124 if(rd.type.has_anchor())
128 _c4dbgp(
"gathering anchors and refs: finished");
131 id_type ReferenceResolver::lookup_(RefData
const* C4_RESTRICT ra)
137 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ra->type.is_key_ref() || ra->type.is_val_ref(), m_tree, ra->node);
138 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ra->type.is_key_ref() != ra->type.is_val_ref(), m_tree, ra->node);
140 _c4dbgpf(
"instance[{}:node{}]: lookup from node={}...", instance, node, ra->node);
141 if(ra->type.is_val_ref())
143 refname = m_tree->val_ref(ra->node);
144 _c4dbgpf(
"instance[{}:node{}]: valref: '{}'", instance, node, refname);
148 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ra->type.is_key_ref(), m_tree, ra->node);
149 refname = m_tree->key_ref(ra->node);
150 _c4dbgpf(
"instance[{}:node{}]: keyref: '{}'", instance, node, refname);
152 while(ra->prev_anchor !=
NONE)
154 ra = &m_refs[ra->prev_anchor];
155 _c4dbgpf(
"instance[{}:node{}]: lookup '{}' at [{}:node{}]: keyref='{}' valref='{}'", instance, node, refname, ra-m_refs.m_stack, ra->node,
156 (m_tree->has_key_anchor(ra->node) ? m_tree->key_anchor(ra->node) : csubstr(
"~")),
157 (m_tree->has_val_anchor(ra->node) ? m_tree->val_anchor(ra->node) : csubstr(
"~")));
158 if(m_tree->has_anchor(ra->node, refname))
160 _c4dbgpf(
"instance[{}:node{}]: got it at [{}:node{}]!", instance, node, ra-m_refs.m_stack, ra->node);
164 _RYML_ERR_VISIT_(m_tree->m_callbacks, m_tree, ra->node,
"anchor not found: '{}'", refname);
165 C4_UNREACHABLE_AFTER_ERR();
168 void ReferenceResolver::reset_(Tree *t_)
170 if(t_->callbacks() != m_refs.m_callbacks)
172 m_refs.m_callbacks = t_->callbacks();
178 void ReferenceResolver::resolve_()
185 _c4dbgp(
"matching anchors/refs...");
186 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
188 RefData &C4_RESTRICT refdata = m_refs.top(i);
189 if( ! refdata.type.is_ref())
191 refdata.target = lookup_(&refdata);
193 _c4dbgp(
"matching anchors/refs: finished");
196 _c4dbgp(
"modifying tree...");
199 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
201 RefData
const& C4_RESTRICT refdata = m_refs[i];
202 _c4dbgpf(
"instance[{}:node{}]: {}/{}...", i, refdata.node, i+1, e);
203 if( ! refdata.type.is_ref())
205 _c4dbgpf(
"instance[{}:node{}]: is reference!", i, refdata.node);
206 if(refdata.parent_ref !=
NONE)
208 _c4dbgpf(
"instance[{}:node{}] has parent: {}", i, refdata.node, refdata.parent_ref);
209 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref), m_tree, refdata.node);
210 const id_type p = m_tree->parent(refdata.parent_ref);
211 const id_type after = (prev_parent_ref != refdata.parent_ref) ?
214 prev_parent_ref_after;
215 prev_parent_ref = refdata.parent_ref;
216 prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
217 m_tree->remove(refdata.node);
221 _c4dbgpf(
"instance[{}:node{}] has no parent", i, refdata.node, refdata.parent_ref);
222 if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) ==
"<<")
224 _c4dbgpf(
"instance[{}:node{}] is inheriting", i, refdata.node);
225 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->is_keyval(refdata.node), m_tree, refdata.node);
226 const id_type p = m_tree->parent(refdata.node);
227 const id_type after = m_tree->prev_sibling(refdata.node);
228 _c4dbgpf(
"instance[{}:node{}] p={} after={}", i, refdata.node, p, after);
229 m_tree->duplicate_children_no_rep(refdata.target, p, after);
230 m_tree->remove(refdata.node);
232 else if(refdata.type.is_key_ref())
234 _c4dbgpf(
"instance[{}:node{}] is key ref", i, refdata.node);
235 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node), m_tree, refdata.node);
236 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target), m_tree, refdata.node);
237 if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
239 _c4dbgpf(
"instance[{}:node{}] target.anchor==val.anchor=={}", i, refdata.node, m_tree->val_anchor(refdata.target));
240 _RYML_CHECK_VISIT_(m_tree->m_callbacks, !m_tree->is_container(refdata.target), m_tree, refdata.target);
241 _RYML_CHECK_VISIT_(m_tree->m_callbacks, m_tree->has_val(refdata.target), m_tree, refdata.target);
242 const type_bits existing_style_flags =
VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
244 m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
245 m_tree->_add_flags(refdata.node,
KEY | (existing_style_flags >> 1u));
249 _c4dbgpf(
"instance[{}:node{}] don't inherit container flags", i, refdata.node);
250 _RYML_CHECK_BASIC_(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
251 m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
253 const type_bits existing_style_flags =
KEY_STYLE & m_tree->_p(refdata.target)->m_type.type;
254 m_tree->_add_flags(refdata.node,
KEY | existing_style_flags);
259 _c4dbgpf(
"instance[{}:node{}] is val ref", i, refdata.node);
260 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, refdata.type.is_val_ref(), m_tree, refdata.node);
261 if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
263 _c4dbgpf(
"instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->key_anchor(refdata.target));
264 _RYML_CHECK_BASIC_(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
265 _RYML_CHECK_BASIC_(m_tree->m_callbacks, m_tree->has_val(refdata.target));
267 const type_bits existing_style_flags = (
KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
269 m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
270 m_tree->_add_flags(refdata.node,
VAL | (existing_style_flags << 1u));
274 _c4dbgpf(
"instance[{}:node{}] duplicate contents", i, refdata.node);
275 m_tree->duplicate_contents(refdata.target, refdata.node);
285 _c4dbgp(
"resolving references...");
291 gather_anchors_and_refs_();
300 _c4dbgp(
"clearing anchors/refs");
301 auto clear_ = [
this]{
302 for(
auto const& C4_RESTRICT ar : m_refs)
304 m_tree->rem_anchor_ref(ar.node);
305 if(ar.parent_ref !=
NONE)
306 if(m_tree->type(ar.parent_ref) !=
NOTYPE)
307 m_tree->remove(ar.parent_ref);
315 gather_anchors_and_refs_();
317 _c4dbgp(
"clearing anchors/refs: finished");
323 _c4dbgp(
"resolving references: finished");
Common utilities and infrastructure used by ryml.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
@ VALANCH
the val has an &anchor
@ NOTYPE
no node type or style is set
@ VALREF
a *reference: the val references an &anchor
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
@ KEYREF
a *reference: the key references an &anchor
@ KEYANCH
the key has an &anchor
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...
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
void resolve(Tree *tree, bool clear_anchors=true)
Resolve references: for each reference, look for a matching anchor, and copy its contents to the ref ...