3#include "c4/yml/detail/dbgprint.hpp"
5#include "c4/yml/detail/print.hpp"
7#define _c4dbg_tree(...)
8#define _c4dbg_node(...)
19 NodeType ty = m_tree->type(n);
20 c += ty.has_key_anchor();
21 c += ty.has_val_anchor();
24 c += ty.has_key() && m_tree->key(n) ==
"<<";
25 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
26 c += count_anchors_and_refs_(ch);
30void ReferenceResolver::gather_anchors_and_refs_(
id_type n)
32 NodeType ty = m_tree->type(n);
36 if(!ty.is_key_quoted() && m_tree->key(n) ==
"<<")
38 _c4dbgpf(
"node[{}]: key is <<", n);
43 _c4dbgpf(
"node[{}]: instance[{}]: val ref, inheriting! '{}'", n, m_refs.size(), m_tree->val_ref(n));
49 _c4dbgpf(
"node[{}]: not ref!", n);
56 _c4dbgpf(
"node[{}]: is seq!", n);
57 for(
id_type ich = m_tree->first_child(n); ich !=
NONE; ich = m_tree->next_sibling(ich))
59 _c4dbgpf(
"node[{}]: instance [{}]: val ref, inheriting multiple: {} '{}'", n, m_refs.size(), ich, m_tree->val_ref(ich));
60 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, !m_tree->is_container(ich), m_tree, ich);
61 m_refs.push({
VALREF, ich,
NONE,
NONE, n, m_tree->next_sibling(n)});
67 RYML_ERR_VISIT_CB_(m_tree->m_callbacks, m_tree, n,
"refs for << must be either val or seq");
70 else if(ty.is_key_ref())
72 _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{
"-"});
73 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_tree->key(n) !=
"<<", m_tree, n);
74 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->key(n).ends_with(m_tree->key_ref(n)), m_tree, n);
79 if(ty.is_val_ref() && (!ty.has_key() || m_tree->key(n) !=
"<<"))
81 _c4dbgpf(
"node[{}]: instance[{}]: val ref: '{}'", n, m_refs.size(), m_tree->val_ref(n));
82 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (!ty.has_val()) || m_tree->val(n).ends_with(m_tree->val_ref(n)), m_tree, n);
86 if(ty.has_key_anchor())
88 _c4dbgpf(
"node[{}]: instance[{}]: key anchor: '{}'", n, m_refs.size(), m_tree->key_anchor(n));
89 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ty.has_key(), m_tree, n);
92 if(ty.has_val_anchor())
94 _c4dbgpf(
"node[{}]: instance[{}]: val anchor: '{}'", n, m_refs.size(), m_tree->val_anchor(n));
95 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ty.has_val() || ty.is_container(), m_tree, n);
99 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
100 gather_anchors_and_refs_(ch);
103void ReferenceResolver::gather_anchors_and_refs_()
105 _c4dbgp(
"gathering anchors and refs...");
108 id_type num_anchors_and_refs = count_anchors_and_refs_(m_tree->root_id());
109 if(!num_anchors_and_refs)
111 m_refs.reserve(num_anchors_and_refs);
115 gather_anchors_and_refs_(m_tree->root_id());
117 _c4dbgpf(
"found {} anchors/refs", m_refs.size());
122 for(
auto &rd : m_refs)
124 rd.prev_anchor = prev_anchor;
125 if(rd.type.has_anchor())
129 _c4dbgp(
"gathering anchors and refs: finished");
132id_type ReferenceResolver::lookup_(RefData
const* C4_RESTRICT ra)
138 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ra->type.is_key_ref() || ra->type.is_val_ref(), m_tree, ra->node);
139 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ra->type.is_key_ref() != ra->type.is_val_ref(), m_tree, ra->node);
141 _c4dbgpf(
"instance[{}:node{}]: lookup from node={}...", instance, node, ra->node);
142 if(ra->type.is_val_ref())
144 refname = m_tree->val_ref(ra->node);
145 _c4dbgpf(
"instance[{}:node{}]: valref: '{}'", instance, node, refname);
149 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ra->type.is_key_ref(), m_tree, ra->node);
150 refname = m_tree->key_ref(ra->node);
151 _c4dbgpf(
"instance[{}:node{}]: keyref: '{}'", instance, node, refname);
153 while(ra->prev_anchor !=
NONE)
155 ra = &m_refs[ra->prev_anchor];
156 _c4dbgpf(
"instance[{}:node{}]: lookup '{}' at [{}:node{}]: keyref='{}' valref='{}'", instance, node, refname, ra-m_refs.m_stack, ra->node,
157 (m_tree->has_key_anchor(ra->node) ? m_tree->key_anchor(ra->node) :
csubstr(
"~")),
158 (m_tree->has_val_anchor(ra->node) ? m_tree->val_anchor(ra->node) :
csubstr(
"~")));
159 if(m_tree->has_anchor(ra->node, refname))
161 _c4dbgpf(
"instance[{}:node{}]: got it at [{}:node{}]!", instance, node, ra-m_refs.m_stack, ra->node);
165 RYML_ERR_VISIT_CB_(m_tree->m_callbacks, m_tree, ra->node,
"anchor not found: '{}'", refname);
166 C4_UNREACHABLE_AFTER_ERR();
169void ReferenceResolver::reset_(Tree *t_)
171 if(t_->callbacks() != m_refs.m_callbacks)
173 m_refs.m_callbacks = t_->callbacks();
179void ReferenceResolver::resolve_()
186 _c4dbgp(
"matching anchors/refs...");
187 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
189 RefData &C4_RESTRICT refdata = m_refs.top(i);
190 if( ! refdata.type.is_ref())
192 refdata.target = lookup_(&refdata);
194 _c4dbgp(
"matching anchors/refs: finished");
197 _c4dbgp(
"modifying tree...");
200 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
202 RefData
const& C4_RESTRICT refdata = m_refs[i];
203 _c4dbgpf(
"instance[{}:node{}]: {}/{}...", i, refdata.node, i+1, e);
204 if( ! refdata.type.is_ref())
206 _c4dbgpf(
"instance[{}:node{}]: is reference!", i, refdata.node);
207 NodeType nty = m_tree->type(refdata.node);
208 if(refdata.parent_ref !=
NONE)
210 _c4dbgpf(
"instance[{}:node{}] has parent: {}", i, refdata.node, refdata.parent_ref);
211 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref), m_tree, refdata.node);
212 const id_type p = m_tree->parent(refdata.parent_ref);
213 const id_type after = (prev_parent_ref != refdata.parent_ref) ?
216 prev_parent_ref_after;
217 prev_parent_ref = refdata.parent_ref;
218 prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
219 m_tree->remove(refdata.node);
223 _c4dbgpf(
"instance[{}:node{}] has no parent", i, refdata.node, refdata.parent_ref);
224 if(nty.has_key() && m_tree->key(refdata.node) ==
"<<")
226 _c4dbgpf(
"instance[{}:node{}] is inheriting", i, refdata.node);
227 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, nty.is_keyval(), m_tree, refdata.node);
228 const id_type p = m_tree->parent(refdata.node);
229 const id_type after = m_tree->prev_sibling(refdata.node);
230 _c4dbgpf(
"instance[{}:node{}] p={} after={}", i, refdata.node, p, after);
231 m_tree->duplicate_children_no_rep(refdata.target, p, after);
232 m_tree->remove(refdata.node);
234 else if(refdata.type.is_key_ref())
236 _c4dbgpf(
"instance[{}:node{}] is key ref", i, refdata.node);
237 NodeType tty = m_tree->type(refdata.target);
238 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, nty.is_key_ref(), m_tree, refdata.node);
239 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, tty.has_key_anchor() || tty.has_val_anchor(), m_tree, refdata.node);
240 if(tty.has_val_anchor() && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
242 _c4dbgpf(
"instance[{}:node{}] target.anchor==val.anchor=={}", i, refdata.node, m_tree->val_anchor(refdata.target));
243 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, !m_tree->is_container(refdata.target), m_tree, refdata.target);
244 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->has_val(refdata.target), m_tree, refdata.target);
245 const type_bits existing_style_flags =
VAL_STYLE & m_tree->_p(refdata.target)->m_type.m_bits;
247 m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
248 m_tree->_add_flags(refdata.node,
KEY | (existing_style_flags >> 1u));
252 _c4dbgpf(
"instance[{}:node{}] don't inherit container flags", i, refdata.node);
253 RYML_CHECK_BASIC_CB_(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
254 m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
256 const type_bits existing_style_flags =
KEY_STYLE & m_tree->_p(refdata.target)->m_type.m_bits;
257 m_tree->_add_flags(refdata.node,
KEY | existing_style_flags);
262 _c4dbgpf(
"instance[{}:node{}] is val ref", i, refdata.node);
263 NodeType tty = m_tree->type(refdata.target);
264 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, refdata.type.is_val_ref(), m_tree, refdata.node);
265 if(tty.has_key_anchor() && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
267 _c4dbgpf(
"instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->key_anchor(refdata.target));
268 RYML_CHECK_BASIC_CB_(m_tree->m_callbacks, !tty.is_container());
269 RYML_CHECK_BASIC_CB_(m_tree->m_callbacks, tty.has_val());
271 const type_bits existing_style_flags = (
KEY_STYLE) & m_tree->_p(refdata.target)->m_type.m_bits;
273 m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
274 m_tree->_add_flags(refdata.node,
VAL | (existing_style_flags << 1u));
278 _c4dbgpf(
"instance[{}:node{}] duplicate contents", i, refdata.node);
279 m_tree->duplicate_contents(refdata.target, refdata.node);
289 _c4dbgp(
"resolving references...");
295 gather_anchors_and_refs_();
304 _c4dbgp(
"clearing anchors/refs");
305 auto clear_ = [
this]{
306 for(
auto const& C4_RESTRICT ar : m_refs)
308 m_tree->rem_anchor_ref(ar.node);
309 if(ar.parent_ref !=
NONE)
310 if(m_tree->type(ar.parent_ref) !=
NOTYPE)
311 m_tree->remove(ar.parent_ref);
319 gather_anchors_and_refs_();
321 _c4dbgp(
"clearing anchors/refs: finished");
327 _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
@ KEY
the scalar to the left of : in a map's member
@ VAL_STYLE
mask of VALQUO|VAL_PLAIN : all the val 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 KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!...
@ KEYREF
a *reference: the key references an &anchor
@ KEYANCH
the key has an &anchor
basic_substring< const char > csubstr
an immutable string view
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...
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 ...