4 #include "c4/yml/detail/parser_dbg.hpp"
6 #include "c4/yml/detail/print.hpp"
8 #define _c4dbg_tree(...)
9 #define _c4dbg_node(...)
18 c += m_tree->has_key_anchor(n);
19 c += m_tree->has_val_anchor(n);
20 c += m_tree->is_key_ref(n);
21 c += m_tree->is_val_ref(n);
22 c += m_tree->has_key(n) && m_tree->key(n) ==
"<<";
23 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
24 c += count_anchors_and_refs_(ch);
28 void ReferenceResolver::gather_anchors_and_refs__(
id_type n)
31 if(m_tree->has_key(n))
33 if(m_tree->key(n) ==
"<<")
35 _c4dbgpf(
"node[{}]: key is <<", n);
36 if(m_tree->has_val(n))
38 if(m_tree->is_val_ref(n))
40 _c4dbgpf(
"node[{}]: val ref, inheriting!", n);
46 _c4dbgpf(
"node[{}]: not ref!", n);
49 else if(m_tree->is_seq(n))
53 _c4dbgpf(
"node[{}]: is seq!", n);
54 for(
id_type ich = m_tree->first_child(n); ich !=
NONE; ich = m_tree->next_sibling(ich))
56 _c4dbgpf(
"node[{}]: val ref, inheriting multiple: {}", n, ich);
57 if(m_tree->is_container(ich))
59 detail::_report_err(m_tree->m_callbacks,
"ERROR: node {} child {}: refs for << cannot be containers.'", n, ich);
60 C4_UNREACHABLE_AFTER_ERR();
62 m_refs.push({
VALREF, ich,
NONE,
NONE, n, m_tree->next_sibling(n)});
68 detail::_report_err(m_tree->m_callbacks,
"ERROR: node {}: refs for << must be either val or seq", n);
69 C4_UNREACHABLE_AFTER_ERR();
72 else if(m_tree->is_key_ref(n))
74 _c4dbgpf(
"node[{}]: key ref: '{}'", n, m_tree->key_ref(n));
75 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->key(n) !=
"<<");
76 _RYML_CB_CHECK(m_tree->m_callbacks, (!m_tree->has_key(n)) || m_tree->key(n).ends_with(m_tree->key_ref(n)));
81 if(m_tree->is_val_ref(n) && (!m_tree->has_key(n) || m_tree->key(n) !=
"<<"))
83 _c4dbgpf(
"node[{}]: val ref: '{}'", n, m_tree->val_ref(n));
84 RYML_CHECK((!m_tree->has_val(n)) || m_tree->val(n).ends_with(m_tree->val_ref(n)));
88 if(m_tree->has_key_anchor(n))
90 _c4dbgpf(
"node[{}]: key anchor: '{}'", n, m_tree->key_anchor(n));
91 RYML_CHECK(m_tree->has_key(n));
94 if(m_tree->has_val_anchor(n))
96 _c4dbgpf(
"node[{}]: val anchor: '{}'", n, m_tree->val_anchor(n));
97 RYML_CHECK(m_tree->has_val(n) || m_tree->is_container(n));
101 for(
id_type ch = m_tree->first_child(n); ch !=
NONE; ch = m_tree->next_sibling(ch))
102 gather_anchors_and_refs__(ch);
105 void ReferenceResolver::gather_anchors_and_refs_()
107 _c4dbgp(
"gathering anchors and refs...");
110 id_type num_anchors_and_refs = count_anchors_and_refs_(m_tree->root_id());
111 if(!num_anchors_and_refs)
113 m_refs.reserve(num_anchors_and_refs);
117 gather_anchors_and_refs__(m_tree->root_id());
119 _c4dbgpf(
"found {} anchors/refs", m_refs.size());
124 for(
auto &rd : m_refs)
126 rd.prev_anchor = prev_anchor;
127 if(rd.type.has_anchor())
131 _c4dbgp(
"gathering anchors and refs: finished");
134 id_type ReferenceResolver::lookup_(RefData *C4_RESTRICT ra)
136 RYML_ASSERT(ra->type.is_key_ref() || ra->type.is_val_ref());
137 RYML_ASSERT(ra->type.is_key_ref() != ra->type.is_val_ref());
139 if(ra->type.is_val_ref())
141 refname = m_tree->val_ref(ra->node);
145 RYML_ASSERT(ra->type.is_key_ref());
146 refname = m_tree->key_ref(ra->node);
148 while(ra->prev_anchor !=
NONE)
150 ra = &m_refs[ra->prev_anchor];
151 if(m_tree->has_anchor(ra->node, refname))
154 detail::_report_err(m_tree->m_callbacks,
"ERROR: anchor not found: '{}'", refname);
155 C4_UNREACHABLE_AFTER_ERR();
158 void ReferenceResolver::reset_(Tree *t_)
160 if(t_->callbacks() != m_refs.m_callbacks)
162 m_refs.m_callbacks = t_->callbacks();
170 _c4dbgp(
"resolving references...");
176 gather_anchors_and_refs_();
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 {}/{}...", i, e);
203 if( ! refdata.type.is_ref())
205 _c4dbgpf(
"instance {} is reference!", i);
206 if(refdata.parent_ref !=
NONE)
208 _c4dbgpf(
"ref {} has parent: {}", i, refdata.parent_ref);
209 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref));
210 const id_type p = m_tree->parent(refdata.parent_ref);
212 if(prev_parent_ref != refdata.parent_ref)
214 after = refdata.parent_ref;
215 prev_parent_ref_after = after;
219 after = prev_parent_ref_after;
221 prev_parent_ref = refdata.parent_ref;
222 prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
223 m_tree->remove(refdata.node);
227 _c4dbgpf(
"ref {} has no parent", i, refdata.parent_ref);
228 if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) ==
"<<")
230 _c4dbgpf(
"ref {} is inheriting", i);
231 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_keyval(refdata.node));
232 const id_type p = m_tree->parent(refdata.node);
233 const id_type after = m_tree->prev_sibling(refdata.node);
234 m_tree->duplicate_children_no_rep(refdata.target, p, after);
235 m_tree->remove(refdata.node);
237 else if(refdata.type.is_key_ref())
239 _c4dbgpf(
"ref {} is key ref", i);
240 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node));
241 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target));
242 if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
244 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
245 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
246 const type_bits existing_style_flags =
VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
248 m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
249 m_tree->_add_flags(refdata.node,
KEY | (existing_style_flags >> 1u));
253 _RYML_CB_CHECK(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.type;
257 m_tree->_add_flags(refdata.node,
KEY | existing_style_flags);
262 _c4dbgpf(
"ref {} is val ref", i);
263 _RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
264 if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
266 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
267 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
269 const type_bits existing_style_flags = (
KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
271 m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
272 m_tree->_add_flags(refdata.node,
VAL | (existing_style_flags << 1u));
276 m_tree->duplicate_contents(refdata.target, refdata.node);
281 _c4dbgp(
"modifying tree: finished");
284 _c4dbgp(
"clearing anchors/refs");
285 for(
auto const& C4_RESTRICT ar : m_refs)
287 m_tree->rem_anchor_ref(ar.node);
288 if(ar.parent_ref !=
NONE)
289 if(m_tree->type(ar.parent_ref) !=
NOTYPE)
290 m_tree->remove(ar.parent_ref);
292 _c4dbgp(
"clearing anchors/refs: finished");
297 _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
is member of a map, must have non-empty key
@ 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...
void resolve(Tree *t_)
Resolve references: for each reference, look for a matching anchor, and copy its contents to the ref ...