1 #ifndef _C4_YML_EMIT_DEF_HPP_
2 #define _C4_YML_EMIT_DEF_HPP_
4 #ifndef _C4_YML_EMIT_HPP_
9 #ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
10 #include "c4/yml/detail/parser_dbg.hpp"
16 template<
class Writer>
32 _do_visit_json(
id, 0);
34 _RYML_CB_ERR(m_tree->callbacks(),
"unknown emit type");
36 return this->Writer::_get(error_on_excess);
42 template<
class Writer>
48 auto dispatch = [
this](
id_type node){
51 _do_visit_flow_sl(node, 0);
53 _do_visit_flow_ml(node, 0);
56 _do_visit_block(node, 0);
59 if(!m_tree->is_root(
id))
61 if(m_tree->is_container(
id) && !m_tree->type(
id).is_flow())
64 if(m_tree->has_key(
id))
66 this->Writer::_do_write(m_tree->key(
id));
67 this->Writer::_do_write(
":\n");
70 _do_visit_block_container(
id, 0, ilevel, ilevel);
75 TagDirectiveRange tagds = m_tree->tag_directives();
76 auto write_tag_directives = [&tagds,
this](
const id_type next_node){
77 TagDirective
const* C4_RESTRICT end = tagds.b;
80 if(end->next_node_id > next_node)
84 const id_type parent = m_tree->parent(next_node);
85 for( ; tagds.b != end; ++tagds.b)
87 if(next_node != m_tree->first_child(parent))
88 this->Writer::_do_write(
"...\n");
89 this->Writer::_do_write(
"%TAG ");
90 this->Writer::_do_write(tagds.b->handle);
91 this->Writer::_do_write(
' ');
92 this->Writer::_do_write(tagds.b->prefix);
93 this->Writer::_do_write(
'\n');
96 if(m_tree->is_stream(
id))
98 const id_type first_child = m_tree->first_child(
id);
99 if(first_child !=
NONE)
100 write_tag_directives(first_child);
101 for(
id_type child = first_child; child !=
NONE; child = m_tree->next_sibling(child))
104 if(m_tree->is_doc(child) && m_tree->type(child).is_flow_sl())
105 this->Writer::_do_write(
'\n');
106 if(m_tree->next_sibling(child) !=
NONE)
107 write_tag_directives(m_tree->next_sibling(child));
110 else if(m_tree->is_container(
id))
114 else if(m_tree->is_doc(
id))
116 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_container(
id));
117 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_val(
id));
120 else if(m_tree->is_keyval(
id))
123 this->Writer::_do_write(
": ");
125 if(!m_tree->type(
id).is_flow())
126 this->Writer::_do_write(
'\n');
128 else if(m_tree->is_val(
id))
132 if(!m_tree->type(
id).is_flow())
133 this->Writer::_do_write(
'\n');
135 else if(m_tree->type(
id) ==
NOTYPE)
141 _RYML_CB_ERR(m_tree->callbacks(),
"unknown type");
145 #define _rymlindent_nextline() this->_indent(ilevel + 1);
147 template<
class Writer>
148 void Emitter<Writer>::_write_doc(
id_type id)
150 RYML_ASSERT(m_tree->is_doc(
id));
151 RYML_ASSERT(!m_tree->has_key(
id));
152 if(!m_tree->is_root(
id))
154 RYML_ASSERT(m_tree->is_stream(m_tree->parent(
id)));
155 this->Writer::_do_write(
"---");
158 if(!m_tree->has_val(
id))
160 const bool tag = m_tree->has_val_tag(
id);
161 const bool anchor = m_tree->has_val_anchor(
id);
166 else if(!tag && anchor)
168 if(!m_tree->is_root(
id))
169 this->Writer::_do_write(
' ');
170 this->Writer::_do_write(
'&');
171 this->Writer::_do_write(m_tree->val_anchor(
id));
172 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
173 if(m_tree->has_children(
id) && m_tree->is_root(
id))
174 this->Writer::_do_write(
'\n');
177 else if(tag && !anchor)
179 if(!m_tree->is_root(
id))
180 this->Writer::_do_write(
' ');
181 _write_tag(m_tree->val_tag(
id));
182 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
183 if(m_tree->has_children(
id) && m_tree->is_root(
id))
184 this->Writer::_do_write(
'\n');
189 if(!m_tree->is_root(
id))
190 this->Writer::_do_write(
' ');
191 _write_tag(m_tree->val_tag(
id));
192 this->Writer::_do_write(
" &");
193 this->Writer::_do_write(m_tree->val_anchor(
id));
194 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
195 if(m_tree->has_children(
id) && m_tree->is_root(
id))
196 this->Writer::_do_write(
'\n');
202 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_val(
id));
205 const csubstr val = m_tree->val(
id);
206 const bool preceded_by_3_dashes = !m_tree->is_root(
id);
208 const bool is_plain = m_tree->type(
id).is_val_plain();
209 const bool is_ambiguous = (is_plain || !style_marks)
210 && ((val.begins_with(
"...") || val.begins_with(
"---"))
212 (val.find(
'\n') !=
npos));
213 if(preceded_by_3_dashes)
215 if(val.len == 0 && !m_tree->has_val_anchor(
id) && !m_tree->has_val_tag(
id))
217 this->Writer::_do_write(
'\n');
220 else if(val.len && is_ambiguous)
222 this->Writer::_do_write(
'\n');
226 this->Writer::_do_write(
' ');
236 if(val.len && m_tree->is_root(
id))
237 this->Writer::_do_write(
'\n');
239 if(!m_tree->is_root(
id))
240 this->Writer::_do_write(
'\n');
243 template<
class Writer>
246 const bool prev_flow = m_flow;
248 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node));
249 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node));
250 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
251 if(C4_UNLIKELY(depth > m_opts.max_depth()))
252 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
254 if(m_tree->is_doc(node))
257 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
258 if(!m_tree->has_children(node))
263 if(m_tree->is_map(node))
265 this->Writer::_do_write(
'{');
269 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
270 this->Writer::_do_write(
'[');
274 else if(m_tree->is_container(node))
276 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node));
280 if(m_tree->has_key(node))
282 _writek(node, ilevel);
283 this->Writer::_do_write(
':');
287 if(m_tree->has_val_tag(node))
290 this->Writer::_do_write(
' ');
291 _write_tag(m_tree->val_tag(node));
295 if(m_tree->has_val_anchor(node))
298 this->Writer::_do_write(
' ');
299 this->Writer::_do_write(
'&');
300 this->Writer::_do_write(m_tree->val_anchor(node));
305 this->Writer::_do_write(
' ');
307 if(m_tree->is_map(node))
309 this->Writer::_do_write(
'{');
313 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
314 this->Writer::_do_write(
'[');
318 for(
id_type child = m_tree->first_child(node), count = 0; child !=
NONE; child = m_tree->next_sibling(child))
321 this->Writer::_do_write(
',');
322 if(m_tree->is_keyval(child))
324 _writek(child, ilevel);
325 this->Writer::_do_write(
": ");
326 _writev(child, ilevel);
328 else if(m_tree->is_val(child))
330 _writev(child, ilevel);
335 _do_visit_flow_sl(child, depth + 1, ilevel + 1);
339 if(m_tree->is_map(node))
341 this->Writer::_do_write(
'}');
343 else if(m_tree->is_seq(node))
345 this->Writer::_do_write(
']');
350 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702)
352 template<class Writer>
358 C4_UNUSED(do_indent);
360 #ifdef THIS_IS_A_WORK_IN_PROGRESS
361 if(C4_UNLIKELY(depth > m_opts.max_depth()))
362 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
363 const bool prev_flow = m_flow;
370 template<
class Writer>
371 void Emitter<Writer>::_do_visit_block_container(
id_type node,
id_type depth,
id_type level,
bool do_indent)
373 if(m_tree->is_seq(node))
375 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
377 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child));
378 if(m_tree->is_val(child))
380 _indent(level, do_indent);
381 this->Writer::_do_write(
"- ");
382 _writev(child, level);
383 this->Writer::_do_write(
'\n');
387 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child));
388 NodeType ty = m_tree->
type(child);
391 _indent(level, do_indent);
392 this->Writer::_do_write(
"- ");
393 _do_visit_flow_sl(child, depth+1, 0u);
394 this->Writer::_do_write(
'\n');
396 else if(ty.is_flow_ml())
398 _indent(level, do_indent);
399 this->Writer::_do_write(
"- ");
400 _do_visit_flow_ml(child, depth+1, 0u, do_indent);
401 this->Writer::_do_write(
'\n');
405 _do_visit_block(child, depth+1, level, do_indent);
413 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node));
414 for(
id_type ich = m_tree->first_child(node); ich !=
NONE; ich = m_tree->next_sibling(ich))
416 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich));
417 if(m_tree->is_keyval(ich))
419 _indent(level, do_indent);
421 this->Writer::_do_write(
": ");
423 this->Writer::_do_write(
'\n');
427 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich));
428 NodeType ty = m_tree->type(ich);
431 _indent(level, do_indent);
432 _do_visit_flow_sl(ich, depth+1, 0u);
433 this->Writer::_do_write(
'\n');
435 else if(ty.is_flow_ml())
437 _indent(level, do_indent);
438 _do_visit_flow_ml(ich, depth+1, 0u);
439 this->Writer::_do_write(
'\n');
443 _do_visit_block(ich, depth+1, level, do_indent);
451 template<
class Writer>
454 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node));
455 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node));
456 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
457 if(C4_UNLIKELY(depth > m_opts.max_depth()))
458 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
459 if(m_tree->is_doc(node))
462 if(!m_tree->has_children(node))
465 else if(m_tree->is_container(node))
467 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node));
470 if(m_tree->has_key(node))
472 _indent(ilevel, do_indent);
473 _writek(node, ilevel);
474 this->Writer::_do_write(
':');
477 else if(!m_tree->is_root(node))
479 _indent(ilevel, do_indent);
480 this->Writer::_do_write(
'-');
484 if(m_tree->has_val_tag(node))
487 this->Writer::_do_write(
' ');
488 _write_tag(m_tree->val_tag(node));
493 if(m_tree->has_val_anchor(node))
496 this->Writer::_do_write(
' ');
497 this->Writer::_do_write(
'&');
498 this->Writer::_do_write(m_tree->val_anchor(node));
503 if(m_tree->has_children(node))
505 if(m_tree->has_key(node))
508 if(!m_tree->is_root(node) && !nl)
513 if(m_tree->is_seq(node))
514 this->Writer::_do_write(
" []\n");
515 else if(m_tree->is_map(node))
516 this->Writer::_do_write(
" {}\n");
521 this->Writer::_do_write(
' ');
526 this->Writer::_do_write(
'\n');
531 id_type next_level = ilevel + 1;
532 if(m_tree->is_root(node) || m_tree->is_doc(node))
535 _do_visit_block_container(node, depth, next_level, do_indent);
538 C4_SUPPRESS_WARNING_MSVC_POP
541 template<
class Writer>
544 _RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(
id));
545 if(C4_UNLIKELY(depth > m_opts.max_depth()))
546 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
547 if(m_tree->is_keyval(
id))
550 this->Writer::_do_write(
": ");
553 else if(m_tree->is_val(
id))
557 else if(m_tree->is_container(
id))
559 if(m_tree->has_key(
id))
562 this->Writer::_do_write(
": ");
564 if(m_tree->is_seq(
id))
565 this->Writer::_do_write(
'[');
566 else if(m_tree->is_map(
id))
567 this->Writer::_do_write(
'{');
570 for(
id_type ich = m_tree->first_child(
id); ich !=
NONE; ich = m_tree->next_sibling(ich))
572 if(ich != m_tree->first_child(
id))
573 this->Writer::_do_write(
',');
574 _do_visit_json(ich, depth+1);
577 if(m_tree->is_seq(
id))
578 this->Writer::_do_write(
']');
579 else if(m_tree->is_map(
id))
580 this->Writer::_do_write(
'}');
583 template<
class Writer>
584 void Emitter<Writer>::_write(NodeScalar
const& C4_RESTRICT sc, NodeType flags,
id_type ilevel)
586 if( ! sc.tag.empty())
589 this->Writer::_do_write(
' ');
591 if(flags.has_anchor())
593 RYML_ASSERT(flags.is_ref() != flags.has_anchor());
594 RYML_ASSERT( ! sc.anchor.empty());
595 this->Writer::_do_write(
'&');
596 this->Writer::_do_write(sc.anchor);
597 this->Writer::_do_write(
' ');
599 else if(flags.is_ref())
601 if(sc.anchor !=
"<<")
602 this->Writer::_do_write(
'*');
603 this->Writer::_do_write(sc.anchor);
604 if(flags.is_key_ref())
605 this->Writer::_do_write(
' ');
616 _write_scalar_literal(sc.scalar, ilevel, flags.has_key());
620 _write_scalar_folded(sc.scalar, ilevel, flags.has_key());
624 _write_scalar_squo(sc.scalar, ilevel);
628 _write_scalar_dquo(sc.scalar, ilevel);
632 if(C4_LIKELY(!(sc.scalar.begins_with(
": ") || sc.scalar.begins_with(
":\t"))))
633 _write_scalar_plain(sc.scalar, ilevel);
635 _write_scalar_squo(sc.scalar, ilevel);
639 _RYML_CB_ERR(m_tree->callbacks(),
"not implemented");
643 template<
class Writer>
644 void Emitter<Writer>::_write_json(NodeScalar
const& C4_RESTRICT sc, NodeType flags)
648 _RYML_CB_ERR(m_tree->callbacks(),
"JSON does not have tags");
649 if(C4_UNLIKELY(flags.has_anchor()))
651 _RYML_CB_ERR(m_tree->callbacks(),
"JSON does not have anchors");
660 _write_scalar_json_dquo(sc.scalar);
662 this->Writer::_do_write(sc.scalar);
667 this->Writer::_do_write(
"\"\"");
669 this->Writer::_do_write(
"null");
673 template<
class Writer>
674 size_t Emitter<Writer>::_write_escaped_newlines(csubstr s,
size_t i)
676 RYML_ASSERT(s.len > i);
677 RYML_ASSERT(s.str[i] ==
'\n');
681 this->Writer::_do_write(
'\n');
684 this->Writer::_do_write(
'\n');
686 }
while(i < s.len && s.str[i] ==
'\n');
687 _RYML_CB_ASSERT(m_tree->callbacks(), i > 0);
689 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] ==
'\n');
695 if(prev == 0 && s.begins_with_any(
" \t"))
697 const size_t pos = s.first_not_of(
'\n', i);
698 return (pos !=
npos) && (s.str[pos] ==
' ' || s.str[pos] ==
'\t');
701 template<
class Writer>
702 size_t Emitter<Writer>::_write_indented_block(csubstr s,
size_t i,
id_type ilevel)
705 _RYML_CB_ASSERT(m_tree->callbacks(), i > 0);
706 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i-1] ==
'\n');
707 _RYML_CB_ASSERT(m_tree->callbacks(), i < s.len);
708 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] ==
' ' || s.str[i] ==
'\t' || s.str[i] ==
'\n');
710 size_t pos = s.find(
"\n ", i);
712 pos = s.find(
"\n\t", i);
718 this->Writer::_do_write(s.range(i, pos));
724 pos = s.find(
'\n', i);
727 const size_t pos2 = s.first_not_of(
'\n', pos);
728 pos = (pos2 !=
npos) ? pos2 : pos;
731 this->Writer::_do_write(s.range(i, pos));
737 template<
class Writer>
738 void Emitter<Writer>::_write_scalar_literal(csubstr s,
id_type ilevel,
bool explicit_key)
740 _RYML_CB_ASSERT(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
742 this->Writer::_do_write(
"? ");
743 csubstr trimmed = s.trimr(
'\n');
744 const size_t numnewlines_at_end = s.len - trimmed.len;
745 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
746 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
748 this->Writer::_do_write(
'|');
749 if(explicit_indentation)
750 this->Writer::_do_write(
'2');
752 if(numnewlines_at_end > 1 || is_newline_only)
753 this->Writer::_do_write(
'+');
754 else if(numnewlines_at_end == 0)
755 this->Writer::_do_write(
'-');
759 this->Writer::_do_write(
'\n');
761 for(
size_t i = 0; i < trimmed.len; ++i)
763 if(trimmed[i] !=
'\n')
766 csubstr since_pos = trimmed.range(pos, i+1);
768 this->Writer::_do_write(since_pos);
771 if(pos < trimmed.len)
774 this->Writer::_do_write(trimmed.sub(pos));
777 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
778 this->Writer::_do_write('\n');
780 this->Writer::_do_write('\n');
783 template<class Writer>
784 void Emitter<Writer>::_write_scalar_folded(csubstr s,
id_type ilevel,
bool explicit_key)
787 this->Writer::_do_write(
"? ");
788 _RYML_CB_ASSERT(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
789 csubstr trimmed = s.trimr(
'\n');
790 const size_t numnewlines_at_end = s.len - trimmed.len;
791 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
792 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
794 this->Writer::_do_write(
'>');
795 if(explicit_indentation)
796 this->Writer::_do_write(
'2');
798 if(numnewlines_at_end == 0)
799 this->Writer::_do_write(
'-');
800 else if(numnewlines_at_end > 1 || is_newline_only)
801 this->Writer::_do_write(
'+');
805 this->Writer::_do_write(
'\n');
807 for(
size_t i = 0; i < trimmed.len; ++i)
809 if(trimmed[i] !=
'\n')
817 this->Writer::_do_write(s.range(pos, i));
818 i = _write_escaped_newlines(s, i);
825 if(s.str[i+1] ==
'\n')
828 i = _write_escaped_newlines(s, i);
833 this->Writer::_do_write(
'\n');
843 this->Writer::_do_write(s.range(pos, i));
844 if(pos > 0 || !s.begins_with_any(" \t"))
845 i = _write_indented_block(s, i, ilevel);
849 if(pos < trimmed.len)
852 this->Writer::_do_write(trimmed.sub(pos));
855 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
856 this->Writer::_do_write('\n');
858 this->Writer::_do_write('\n');
861 template<class Writer>
862 void Emitter<Writer>::_write_scalar_squo(csubstr s,
id_type ilevel)
865 this->Writer::_do_write(
'\'');
866 for(
size_t i = 0; i < s.len; ++i)
870 this->Writer::_do_write(s.range(pos, i));
872 i = _write_escaped_newlines(s, i);
878 else if(s[i] == '\'')
880 csubstr sub = s.range(pos, i+1);
882 this->Writer::_do_write(sub);
883 this->Writer::_do_write(
'\'');
889 this->Writer::_do_write(s.sub(pos));
890 this->Writer::_do_write(
'\'');
893 template<
class Writer>
894 void Emitter<Writer>::_write_scalar_dquo(csubstr s,
id_type ilevel)
897 this->Writer::_do_write(
'"');
898 for(
size_t i = 0; i < s.len; ++i)
900 const char curr = s.str[i];
906 csubstr sub = s.range(pos, i);
907 this->Writer::_do_write(sub);
908 this->Writer::_do_write(
'\\');
909 this->Writer::_do_write(curr);
913 #ifndef prefer_writing_newlines_as_double_newlines
916 csubstr sub = s.range(pos, i);
917 this->Writer::_do_write(sub);
918 this->Writer::_do_write(
"\\n");
928 this->Writer::_do_write(s.range(pos, i));
929 i = _write_escaped_newlines(s, i);
937 size_t first = s.first_not_of(" \t", i);
938 _c4dbgpf("@i={} first={} rem=[{}]~~~{}~~~
", i, first, s.sub(i).len, s.sub(i));
943 this->Writer::_do_write('\\');
944 this->Writer::_do_write(s.range(i, first));
945 this->Writer::_do_write('\\');
952 // escape trailing whitespace before a newline
956 const size_t next = s.first_not_of(" \t\r
", i);
957 if(next != npos && s.str[next] == '\n')
959 csubstr sub = s.range(pos, i);
960 this->Writer::_do_write(sub); // write everything up to (excluding) this char
961 this->Writer::_do_write('\\'); // escape the whitespace
969 csubstr sub = s.range(pos, i);
970 this->Writer::_do_write(sub); // write everything up to (excluding) this char
971 this->Writer::_do_write("\\r
"); // write the escaped char
977 csubstr sub = s.range(pos, i);
978 this->Writer::_do_write(sub); // write everything up to (excluding) this char
979 this->Writer::_do_write("\\b
"); // write the escaped char
985 // write missing characters at the end of the string
987 this->Writer::_do_write(s.sub(pos));
988 this->Writer::_do_write('"');
991 template<class Writer>
992 void Emitter<Writer>::_write_scalar_plain(csubstr s, id_type ilevel)
994 if(C4_UNLIKELY(ilevel == 0 && (s.begins_with("...") || s.begins_with("---"))))
996 _rymlindent_nextline() // indent the next line
999 size_t pos = 0; // tracks the last character that was already written
1000 for(size_t i = 0; i < s.len; ++i)
1002 const char curr = s.str[i];
1005 csubstr sub = s.range(pos, i);
1006 this->Writer::_do_write(sub); // write everything up to (including) this newline
1007 i = _write_escaped_newlines(s, i);
1010 _rymlindent_nextline() // indent the next line
1013 // write missing characters at the end of the string
1015 this->Writer::_do_write(s.sub(pos));
1018 #undef _rymlindent_nextline
1020 template<class Writer>
1021 void Emitter<Writer>::_write_scalar_json_dquo(csubstr s)
1024 this->Writer::_do_write('"');
1025 for(size_t i = 0; i < s.len; ++i)
1030 this->Writer ::_do_write(s.range(pos, i));
1031 this->Writer ::_do_write("\\\"");
1035 this->Writer ::_do_write(s.range(pos, i));
1036 this->Writer ::_do_write("\\n");
1040 this->Writer ::_do_write(s.range(pos, i));
1041 this->Writer ::_do_write("\\t");
1045 this->Writer ::_do_write(s.range(pos, i));
1046 this->Writer ::_do_write("\\\\");
1050 this->Writer ::_do_write(s.range(pos, i));
1051 this->Writer ::_do_write("\\r");
1055 this->Writer ::_do_write(s.range(pos, i));
1056 this->Writer ::_do_write("\\b");
1060 this->Writer ::_do_write(s.range(pos, i));
1061 this->Writer ::_do_write("\\f");
1068 csubstr sub = s.sub(pos);
1069 this->Writer::_do_write(sub);
1071 this->Writer::_do_write('"');
1077 #endif /* _C4_YML_EMIT_DEF_HPP_ */
A stateful emitter, for use with a writer such as WriterBuf, WriterFile, or WriterOStream.
Callbacks const & callbacks() const
id_type root_id()
Get the id of the root node.
#define _rymlindent_nextline()
Utilities to emit YAML and JSON.
substr emit_as(EmitType_e type, Tree const &t, id_type id, bool error_on_excess)
emit!
EmitType_e
Specifies the type of content to emit.
NodeType_e scalar_style_json_choose(csubstr s) noexcept
choose a json style based on the scalar's contents
NodeType_e scalar_style_choose(csubstr s) noexcept
choose a YAML emitting style based on the scalar's contents
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
@ NOTYPE
no node type or style is set
@ KEY_DQUO
mark key scalar as double quoted "
@ KEY
is member of a map, must have non-empty key
@ VAL_FOLDED
mark val scalar as multiline, block folded >
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ KEYTAG
the key has a tag
@ VALTAG
the val has a tag
@ VAL_SQUO
mark val scalar as single quoted '
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ VALQUO
val style is one of ', ", > or |
@ VAL_DQUO
mark val scalar as double quoted "
@ KEY_SQUO
mark key scalar as single quoted '
@ VAL_LITERAL
mark val scalar as multiline, block literal |
@ KEY_LITERAL
mark key scalar as multiline, block literal |
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
@ KEY_FOLDED
mark key scalar as multiline, block folded >
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...
@ npos
a null string position
void error(Callbacks const &cb, const char *msg, size_t msg_len, Location loc)
bool _is_indented_block(csubstr s, size_t prev, size_t i) noexcept
wraps a NodeType_e element with some syntactic sugar and predicates
bool is_flow_ml() const noexcept
bool is_flow_sl() const noexcept