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 const NodeType ty = m_tree->
type(
id);
151 RYML_ASSERT(ty.is_doc());
152 RYML_ASSERT(!ty.has_key());
153 if(!m_tree->is_root(
id))
155 RYML_ASSERT(m_tree->is_stream(m_tree->parent(
id)));
156 this->Writer::_do_write(
"---");
161 const bool tag = ty.has_val_tag();
162 const bool anchor = ty.has_val_anchor();
167 else if(!tag && anchor)
169 if(!m_tree->is_root(
id))
170 this->Writer::_do_write(
' ');
171 this->Writer::_do_write(
'&');
172 this->Writer::_do_write(m_tree->val_anchor(
id));
173 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
174 if(m_tree->has_children(
id) && m_tree->is_root(
id))
175 this->Writer::_do_write(
'\n');
178 else if(tag && !anchor)
180 if(!m_tree->is_root(
id))
181 this->Writer::_do_write(
' ');
182 _write_tag(m_tree->val_tag(
id));
183 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
184 if(m_tree->has_children(
id) && m_tree->is_root(
id))
185 this->Writer::_do_write(
'\n');
190 if(!m_tree->is_root(
id))
191 this->Writer::_do_write(
' ');
192 _write_tag(m_tree->val_tag(
id));
193 this->Writer::_do_write(
" &");
194 this->Writer::_do_write(m_tree->val_anchor(
id));
195 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
196 if(m_tree->has_children(
id) && m_tree->is_root(
id))
197 this->Writer::_do_write(
'\n');
203 _RYML_CB_ASSERT(m_tree->callbacks(), ty.has_val());
206 const csubstr val = m_tree->val(
id);
207 const bool preceded_by_3_dashes = !m_tree->is_root(
id);
209 const bool is_plain = ty.is_val_plain();
210 const bool is_ambiguous = (is_plain || !style_marks)
211 && ((val.begins_with(
"...") || val.begins_with(
"---"))
213 (val.find(
'\n') !=
npos));
214 if(preceded_by_3_dashes)
216 if(is_plain && val.len == 0 && !ty.has_val_anchor() && !ty.has_val_tag())
218 this->Writer::_do_write(
'\n');
221 else if(val.len && is_ambiguous)
223 this->Writer::_do_write(
'\n');
227 this->Writer::_do_write(
' ');
237 if(val.len && m_tree->is_root(
id))
238 this->Writer::_do_write(
'\n');
240 if(!m_tree->is_root(
id))
241 this->Writer::_do_write(
'\n');
244 template<
class Writer>
247 const bool prev_flow = m_flow;
249 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node));
250 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node));
251 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
252 if(C4_UNLIKELY(depth > m_opts.max_depth()))
253 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
255 if(m_tree->is_doc(node))
258 #ifdef RYML_NO_COVERAGE__TO_BE_DELETED
259 if(!m_tree->has_children(node))
264 if(m_tree->is_map(node))
266 this->Writer::_do_write(
'{');
270 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
271 this->Writer::_do_write(
'[');
275 else if(m_tree->is_container(node))
277 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node));
281 if(m_tree->has_key(node))
283 _writek(node, ilevel);
284 this->Writer::_do_write(
':');
288 if(m_tree->has_val_tag(node))
291 this->Writer::_do_write(
' ');
292 _write_tag(m_tree->val_tag(node));
296 if(m_tree->has_val_anchor(node))
299 this->Writer::_do_write(
' ');
300 this->Writer::_do_write(
'&');
301 this->Writer::_do_write(m_tree->val_anchor(node));
306 this->Writer::_do_write(
' ');
308 if(m_tree->is_map(node))
310 this->Writer::_do_write(
'{');
314 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
315 this->Writer::_do_write(
'[');
319 for(
id_type child = m_tree->first_child(node), count = 0; child !=
NONE; child = m_tree->next_sibling(child))
322 this->Writer::_do_write(
',');
323 if(m_tree->is_keyval(child))
325 _writek(child, ilevel);
326 this->Writer::_do_write(
": ");
327 _writev(child, ilevel);
329 else if(m_tree->is_val(child))
331 _writev(child, ilevel);
336 _do_visit_flow_sl(child, depth + 1, ilevel + 1);
340 if(m_tree->is_map(node))
342 this->Writer::_do_write(
'}');
344 else if(m_tree->is_seq(node))
346 this->Writer::_do_write(
']');
351 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702)
353 template<class Writer>
359 C4_UNUSED(do_indent);
361 #ifdef THIS_IS_A_WORK_IN_PROGRESS
362 if(C4_UNLIKELY(depth > m_opts.max_depth()))
363 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
364 const bool prev_flow = m_flow;
371 template<
class Writer>
372 void Emitter<Writer>::_do_visit_block_container(
id_type node,
id_type depth,
id_type level,
bool do_indent)
374 if(m_tree->is_seq(node))
376 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
378 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child));
379 if(m_tree->is_val(child))
381 _indent(level, do_indent);
382 this->Writer::_do_write(
"- ");
383 _writev(child, level);
384 this->Writer::_do_write(
'\n');
388 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child));
389 NodeType ty = m_tree->
type(child);
392 _indent(level, do_indent);
393 this->Writer::_do_write(
"- ");
394 _do_visit_flow_sl(child, depth+1, 0u);
395 this->Writer::_do_write(
'\n');
397 else if(ty.is_flow_ml())
399 _indent(level, do_indent);
400 this->Writer::_do_write(
"- ");
401 _do_visit_flow_ml(child, depth+1, 0u, do_indent);
402 this->Writer::_do_write(
'\n');
406 _do_visit_block(child, depth+1, level, do_indent);
414 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node));
415 for(
id_type ich = m_tree->first_child(node); ich !=
NONE; ich = m_tree->next_sibling(ich))
417 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich));
418 if(m_tree->is_keyval(ich))
420 _indent(level, do_indent);
422 this->Writer::_do_write(
": ");
424 this->Writer::_do_write(
'\n');
428 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich));
429 NodeType ty = m_tree->type(ich);
432 _indent(level, do_indent);
433 _do_visit_flow_sl(ich, depth+1, 0u);
434 this->Writer::_do_write(
'\n');
436 else if(ty.is_flow_ml())
438 _indent(level, do_indent);
439 _do_visit_flow_ml(ich, depth+1, 0u);
440 this->Writer::_do_write(
'\n');
444 _do_visit_block(ich, depth+1, level, do_indent);
452 template<
class Writer>
455 _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_stream(node));
456 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node));
457 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
458 if(C4_UNLIKELY(depth > m_opts.max_depth()))
459 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
460 if(m_tree->is_doc(node))
463 if(!m_tree->has_children(node))
466 else if(m_tree->is_container(node))
468 _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node) || m_tree->is_seq(node));
471 if(m_tree->has_key(node))
473 _indent(ilevel, do_indent);
474 _writek(node, ilevel);
475 this->Writer::_do_write(
':');
478 else if(!m_tree->is_root(node))
480 _indent(ilevel, do_indent);
481 this->Writer::_do_write(
'-');
485 if(m_tree->has_val_tag(node))
488 this->Writer::_do_write(
' ');
489 _write_tag(m_tree->val_tag(node));
494 if(m_tree->has_val_anchor(node))
497 this->Writer::_do_write(
' ');
498 this->Writer::_do_write(
'&');
499 this->Writer::_do_write(m_tree->val_anchor(node));
504 if(m_tree->has_children(node))
506 if(m_tree->has_key(node))
509 if(!m_tree->is_root(node) && !nl)
514 if(m_tree->is_seq(node))
515 this->Writer::_do_write(
" []\n");
516 else if(m_tree->is_map(node))
517 this->Writer::_do_write(
" {}\n");
522 this->Writer::_do_write(
' ');
527 this->Writer::_do_write(
'\n');
532 id_type next_level = ilevel + 1;
533 if(m_tree->is_root(node) || m_tree->is_doc(node))
536 _do_visit_block_container(node, depth, next_level, do_indent);
539 C4_SUPPRESS_WARNING_MSVC_POP
542 template<
class Writer>
545 _RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(
id));
546 if(C4_UNLIKELY(depth > m_opts.max_depth()))
547 _RYML_CB_ERR(m_tree->callbacks(),
"max depth exceeded");
548 if(m_tree->is_keyval(
id))
551 this->Writer::_do_write(
": ");
554 else if(m_tree->is_val(
id))
558 else if(m_tree->is_container(
id))
560 if(m_tree->has_key(
id))
563 this->Writer::_do_write(
": ");
565 if(m_tree->is_seq(
id))
566 this->Writer::_do_write(
'[');
567 else if(m_tree->is_map(
id))
568 this->Writer::_do_write(
'{');
571 for(
id_type ich = m_tree->first_child(
id); ich !=
NONE; ich = m_tree->next_sibling(ich))
573 if(ich != m_tree->first_child(
id))
574 this->Writer::_do_write(
',');
575 _do_visit_json(ich, depth+1);
578 if(m_tree->is_seq(
id))
579 this->Writer::_do_write(
']');
580 else if(m_tree->is_map(
id))
581 this->Writer::_do_write(
'}');
584 template<
class Writer>
585 void Emitter<Writer>::_write(NodeScalar
const& C4_RESTRICT sc, NodeType flags,
id_type ilevel)
587 if( ! sc.tag.empty())
590 this->Writer::_do_write(
' ');
592 if(flags.has_anchor())
594 RYML_ASSERT(flags.is_ref() != flags.has_anchor());
595 RYML_ASSERT( ! sc.anchor.empty());
596 this->Writer::_do_write(
'&');
597 this->Writer::_do_write(sc.anchor);
598 this->Writer::_do_write(
' ');
600 else if(flags.is_ref())
602 if(sc.anchor !=
"<<")
603 this->Writer::_do_write(
'*');
604 this->Writer::_do_write(sc.anchor);
605 if(flags.is_key_ref())
606 this->Writer::_do_write(
' ');
617 _write_scalar_literal(sc.scalar, ilevel, flags.has_key());
621 _write_scalar_folded(sc.scalar, ilevel, flags.has_key());
625 _write_scalar_squo(sc.scalar, ilevel);
629 _write_scalar_dquo(sc.scalar, ilevel);
633 if(C4_LIKELY(!(sc.scalar.begins_with(
": ") || sc.scalar.begins_with(
":\t"))))
634 _write_scalar_plain(sc.scalar, ilevel);
636 _write_scalar_squo(sc.scalar, ilevel);
640 _RYML_CB_ERR(m_tree->callbacks(),
"not implemented");
644 template<
class Writer>
645 void Emitter<Writer>::_write_json(NodeScalar
const& C4_RESTRICT sc, NodeType flags)
649 _RYML_CB_ERR(m_tree->callbacks(),
"JSON does not have tags");
650 if(C4_UNLIKELY(flags.has_anchor()))
652 _RYML_CB_ERR(m_tree->callbacks(),
"JSON does not have anchors");
661 _write_scalar_json_dquo(sc.scalar);
663 this->Writer::_do_write(sc.scalar);
668 this->Writer::_do_write(
"\"\"");
670 this->Writer::_do_write(
"null");
674 template<
class Writer>
675 size_t Emitter<Writer>::_write_escaped_newlines(csubstr s,
size_t i)
677 RYML_ASSERT(s.len > i);
678 RYML_ASSERT(s.str[i] ==
'\n');
682 this->Writer::_do_write(
'\n');
685 this->Writer::_do_write(
'\n');
687 }
while(i < s.len && s.str[i] ==
'\n');
688 _RYML_CB_ASSERT(m_tree->callbacks(), i > 0);
690 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] ==
'\n');
696 if(prev == 0 && s.begins_with_any(
" \t"))
698 const size_t pos = s.first_not_of(
'\n', i);
699 return (pos !=
npos) && (s.str[pos] ==
' ' || s.str[pos] ==
'\t');
702 template<
class Writer>
703 size_t Emitter<Writer>::_write_indented_block(csubstr s,
size_t i,
id_type ilevel)
706 _RYML_CB_ASSERT(m_tree->callbacks(), i > 0);
707 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i-1] ==
'\n');
708 _RYML_CB_ASSERT(m_tree->callbacks(), i < s.len);
709 _RYML_CB_ASSERT(m_tree->callbacks(), s.str[i] ==
' ' || s.str[i] ==
'\t' || s.str[i] ==
'\n');
711 size_t pos = s.find(
"\n ", i);
713 pos = s.find(
"\n\t", i);
719 this->Writer::_do_write(s.range(i, pos));
725 pos = s.find(
'\n', i);
728 const size_t pos2 = s.first_not_of(
'\n', pos);
729 pos = (pos2 !=
npos) ? pos2 : pos;
732 this->Writer::_do_write(s.range(i, pos));
738 template<
class Writer>
739 void Emitter<Writer>::_write_scalar_literal(csubstr s,
id_type ilevel,
bool explicit_key)
741 _RYML_CB_ASSERT(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
743 this->Writer::_do_write(
"? ");
744 csubstr trimmed = s.trimr(
'\n');
745 const size_t numnewlines_at_end = s.len - trimmed.len;
746 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
747 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
749 this->Writer::_do_write(
'|');
750 if(explicit_indentation)
751 this->Writer::_do_write(
'2');
753 if(numnewlines_at_end > 1 || is_newline_only)
754 this->Writer::_do_write(
'+');
755 else if(numnewlines_at_end == 0)
756 this->Writer::_do_write(
'-');
760 this->Writer::_do_write(
'\n');
762 for(
size_t i = 0; i < trimmed.len; ++i)
764 if(trimmed[i] !=
'\n')
767 csubstr since_pos = trimmed.range(pos, i+1);
769 this->Writer::_do_write(since_pos);
772 if(pos < trimmed.len)
775 this->Writer::_do_write(trimmed.sub(pos));
778 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
779 this->Writer::_do_write('\n');
782 this->Writer::_do_write(
'\n');
783 this->_indent(ilevel);
787 template<
class Writer>
788 void Emitter<Writer>::_write_scalar_folded(csubstr s,
id_type ilevel,
bool explicit_key)
791 this->Writer::_do_write(
"? ");
792 _RYML_CB_ASSERT(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
793 csubstr trimmed = s.trimr(
'\n');
794 const size_t numnewlines_at_end = s.len - trimmed.len;
795 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
796 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
798 this->Writer::_do_write(
'>');
799 if(explicit_indentation)
800 this->Writer::_do_write(
'2');
802 if(numnewlines_at_end == 0)
803 this->Writer::_do_write(
'-');
804 else if(numnewlines_at_end > 1 || is_newline_only)
805 this->Writer::_do_write(
'+');
809 this->Writer::_do_write(
'\n');
811 for(
size_t i = 0; i < trimmed.len; ++i)
813 if(trimmed[i] !=
'\n')
821 this->Writer::_do_write(s.range(pos, i));
822 i = _write_escaped_newlines(s, i);
829 if(s.str[i+1] ==
'\n')
832 i = _write_escaped_newlines(s, i);
837 this->Writer::_do_write(
'\n');
847 this->Writer::_do_write(s.range(pos, i));
848 if(pos > 0 || !s.begins_with_any(" \t"))
849 i = _write_indented_block(s, i, ilevel);
853 if(pos < trimmed.len)
856 this->Writer::_do_write(trimmed.sub(pos));
859 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
860 this->Writer::_do_write('\n');
863 this->Writer::_do_write(
'\n');
864 this->_indent(ilevel);
868 template<
class Writer>
869 void Emitter<Writer>::_write_scalar_squo(csubstr s,
id_type ilevel)
872 this->Writer::_do_write(
'\'');
873 for(
size_t i = 0; i < s.len; ++i)
877 this->Writer::_do_write(s.range(pos, i));
879 i = _write_escaped_newlines(s, i);
885 else if(s[i] == '\'')
887 csubstr sub = s.range(pos, i+1);
889 this->Writer::_do_write(sub);
890 this->Writer::_do_write(
'\'');
896 this->Writer::_do_write(s.sub(pos));
897 this->Writer::_do_write(
'\'');
900 template<
class Writer>
901 void Emitter<Writer>::_write_scalar_dquo(csubstr s,
id_type ilevel)
904 this->Writer::_do_write(
'"');
905 for(
size_t i = 0; i < s.len; ++i)
907 const char curr = s.str[i];
913 csubstr sub = s.range(pos, i);
914 this->Writer::_do_write(sub);
915 this->Writer::_do_write(
'\\');
916 this->Writer::_do_write(curr);
920 #ifndef prefer_writing_newlines_as_double_newlines
923 csubstr sub = s.range(pos, i);
924 this->Writer::_do_write(sub);
925 this->Writer::_do_write(
"\\n");
935 this->Writer::_do_write(s.range(pos, i));
936 i = _write_escaped_newlines(s, i);
944 size_t first = s.first_not_of(" \t", i);
945 _c4dbgpf("@i={} first={} rem=[{}]~~~{}~~~
", i, first, s.sub(i).len, s.sub(i));
950 this->Writer::_do_write('\\');
951 this->Writer::_do_write(s.range(i, first));
952 this->Writer::_do_write('\\');
959 // escape trailing whitespace before a newline
963 const size_t next = s.first_not_of(" \t\r
", i);
964 if(next != npos && s.str[next] == '\n')
966 csubstr sub = s.range(pos, i);
967 this->Writer::_do_write(sub); // write everything up to (excluding) this char
968 this->Writer::_do_write('\\'); // escape the whitespace
976 csubstr sub = s.range(pos, i);
977 this->Writer::_do_write(sub); // write everything up to (excluding) this char
978 this->Writer::_do_write("\\r
"); // write the escaped char
984 csubstr sub = s.range(pos, i);
985 this->Writer::_do_write(sub); // write everything up to (excluding) this char
986 this->Writer::_do_write("\\b
"); // write the escaped char
992 // write missing characters at the end of the string
994 this->Writer::_do_write(s.sub(pos));
995 this->Writer::_do_write('"');
998 template<class Writer>
999 void Emitter<Writer>::_write_scalar_plain(csubstr s, id_type ilevel)
1001 if(C4_UNLIKELY(ilevel == 0 && (s.begins_with("...") || s.begins_with("---"))))
1003 _rymlindent_nextline() // indent the next line
1006 size_t pos = 0; // tracks the last character that was already written
1007 for(size_t i = 0; i < s.len; ++i)
1009 const char curr = s.str[i];
1012 csubstr sub = s.range(pos, i);
1013 this->Writer::_do_write(sub); // write everything up to (including) this newline
1014 i = _write_escaped_newlines(s, i);
1017 _rymlindent_nextline() // indent the next line
1020 // write missing characters at the end of the string
1022 this->Writer::_do_write(s.sub(pos));
1025 #undef _rymlindent_nextline
1027 template<class Writer>
1028 void Emitter<Writer>::_write_scalar_json_dquo(csubstr s)
1031 this->Writer::_do_write('"');
1032 for(size_t i = 0; i < s.len; ++i)
1037 this->Writer ::_do_write(s.range(pos, i));
1038 this->Writer ::_do_write("\\\"");
1042 this->Writer ::_do_write(s.range(pos, i));
1043 this->Writer ::_do_write("\\n");
1047 this->Writer ::_do_write(s.range(pos, i));
1048 this->Writer ::_do_write("\\t");
1052 this->Writer ::_do_write(s.range(pos, i));
1053 this->Writer ::_do_write("\\\\");
1057 this->Writer ::_do_write(s.range(pos, i));
1058 this->Writer ::_do_write("\\r");
1062 this->Writer ::_do_write(s.range(pos, i));
1063 this->Writer ::_do_write("\\b");
1067 this->Writer ::_do_write(s.range(pos, i));
1068 this->Writer ::_do_write("\\f");
1075 csubstr sub = s.sub(pos);
1076 this->Writer::_do_write(sub);
1078 this->Writer::_do_write('"');
1084 #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 "
@ 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