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_DBGPRINT_HPP_
10 #include "c4/yml/detail/dbgprint.hpp"
13 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wold-style-cast")
19 template<
class Writer>
40 _RYML_ERR_BASIC_(m_tree->callbacks(),
"unknown emit type");
42 return this->Writer::_get(error_on_excess);
60 template<
class Writer>
66 const bool has_parent = !m_tree->is_root(
id);
67 const bool emit_key = has_parent && ty.
has_key() && m_opts.emit_nonroot_key();
68 const bool emit_dash = has_parent && !ty.
has_key() && !ty.
is_doc() && m_opts.emit_nonroot_dash();
69 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !(emit_key && emit_dash), m_tree,
id);
74 _blck_map_open_entry(
id);
79 _blck_seq_open_entry(
id);
90 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
95 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
100 _visit_blck_container(
id);
111 _blck_close_entry(
id);
116 _blck_close_entry(
id);
120 _top_close_entry(
id);
127 else if(m_tree->is_root(
id)
128 || emit_dash || emit_key
132 _write_pws_and_pend(_PWS_NONE);
139 template<
class Writer>
140 void Emitter<Writer>::_visit_stream(
id_type id)
142 auto write_tag_directives = [
this](
const id_type next_node){
143 const id_type doc = m_tree->ancestor_doc(next_node);
144 const TagDirectiveRange tagds = m_tree->m_tag_directives.lookup_range(doc);
145 if(tagds.e != tagds.b)
147 const id_type parent = m_tree->parent(next_node);
148 if(next_node != m_tree->first_child(parent))
150 _write_pws_and_pend(_PWS_NEWL);
154 for(TagDirective
const& td : tagds)
156 _write_pws_and_pend(_PWS_NONE);
164 const id_type first_child = m_tree->first_child(
id);
165 if(first_child !=
NONE)
166 write_tag_directives(first_child);
168 for(
id_type child = first_child; child !=
NONE; child = m_tree->next_sibling(child))
171 _write_pws_and_pend(_PWS_NONE);
172 _top_open_entry(child);
174 _top_close_entry(child);
175 if(m_tree->is_val(child))
177 if(m_tree->type(child) &
VALNIL)
180 else if(m_tree->is_container(child))
182 if(m_tree->is_flow(child))
185 if(m_tree->next_sibling(child) !=
NONE)
187 write_tag_directives(m_tree->next_sibling(child));
196 template<
class Writer>
197 void Emitter<Writer>::_visit_blck_container(
id_type id)
199 NodeType ty = m_tree->
type(
id);
202 _write_pws_and_pend(_PWS_NONE);
205 else if(ty.is_flow_ml())
211 template<
class Writer>
212 void Emitter<Writer>::_visit_flow_container(
id_type id)
214 NodeType ty = m_tree->type(
id);
217 _write_pws_and_pend(_PWS_NONE);
227 template<
class Writer>
228 void Emitter<Writer>::_visit_doc_val(
id_type id)
232 NodeType ty = m_tree->type(
id);
233 const csubstr val = m_tree->val(
id);
235 const bool is_ambiguous = ((ty &
VAL_PLAIN) || !val_style)
236 && (val.begins_with(
"...") || val.begins_with(
"---"));
240 if(m_pws != _PWS_NONE)
245 _write_pws_and_pend(_PWS_NONE);
246 if(m_tree->is_val_ref(
id))
254 _blck_write_scalar(val, val_style);
265 template<
class Writer>
266 void Emitter<Writer>::_visit_doc(
id_type id)
268 const NodeType ty = m_tree->type(
id);
269 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ty.is_doc(), m_tree,
id);
270 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !ty.has_key(), m_tree,
id);
271 if(ty.is_container())
273 _visit_blck_container(
id);
285 template<
class Writer>
286 void Emitter<Writer>::_top_open_entry(
id_type node)
288 NodeType ty = m_tree->type(node);
289 if(ty.is_doc() && !m_tree->is_root(node))
294 if(ty.has_val_anchor())
296 _write_pws_and_pend(_PWS_SPACE);
298 _write(m_tree->val_anchor(node));
302 _write_pws_and_pend(_PWS_SPACE);
303 _write_tag(m_tree->val_tag(node));
305 if(m_pws == _PWS_SPACE)
309 if(ty.is_val_plain() && !m_tree->val(node).len)
314 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_container(), m_tree, node);
324 template<
class Writer>
325 void Emitter<Writer>::_top_close_entry(
id_type node)
327 if(m_tree->is_val(node) && !(m_tree->type(node) &
VALNIL))
336 template<
class Writer>
337 void Emitter<Writer>::_flow_seq_open_entry(
id_type node)
339 NodeType ty = m_tree->type(node);
340 _write_pws_and_pend(_PWS_NONE);
343 _write_pws_and_pend(_PWS_SPACE);
345 _write(m_tree->val_anchor(node));
349 _write_pws_and_pend(_PWS_SPACE);
350 _write_tag(m_tree->val_tag(node));
357 template<
class Writer>
358 void Emitter<Writer>::_flow_map_open_entry(
id_type node)
360 NodeType ty = m_tree->type(node);
361 _write_pws_and_pend(_PWS_NONE);
362 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key(), m_tree, node);
365 _write_pws_and_pend(_PWS_SPACE);
367 _write(m_tree->key_anchor(node));
371 _write_pws_and_pend(_PWS_SPACE);
372 _write_tag(m_tree->key_tag(node));
376 _write_pws_and_pend(_PWS_SPACE);
377 _write_ref(m_tree->key(node));
381 _write_pws_and_pend(_PWS_NONE);
382 csubstr
key = m_tree->key(node);
387 _write_pws_and_pend(_PWS_SPACE);
391 _write_pws_and_pend(_PWS_SPACE);
393 _write(m_tree->val_anchor(node));
397 _write_pws_and_pend(_PWS_SPACE);
398 _write_tag(m_tree->val_tag(node));
405 template<
class Writer>
406 void Emitter<Writer>::_flow_close_entry_sl(
id_type node,
id_type last_sibling)
408 if(node != last_sibling)
410 _write_pws_and_pend(_PWS_NONE);
415 template<
class Writer>
416 void Emitter<Writer>::_flow_close_entry_ml(
id_type node,
id_type last_sibling)
418 if(node != last_sibling)
420 _write_pws_and_pend(_PWS_NONE);
429 template<
class Writer>
430 void Emitter<Writer>::_blck_seq_open_entry(
id_type node)
432 NodeType ty = m_tree->type(node);
433 _write_pws_and_pend(_PWS_NONE);
434 _write_pws_and_pend(_PWS_SPACE);
436 bool has_tag_or_anchor =
false;
439 has_tag_or_anchor =
true;
440 _write_pws_and_pend(_PWS_SPACE);
442 _write(m_tree->val_anchor(node));
446 has_tag_or_anchor =
true;
447 _write_pws_and_pend(_PWS_SPACE);
448 _write_tag(m_tree->val_tag(node));
450 if(has_tag_or_anchor && ty.is_container())
454 if((ty &
BLOCK) && m_tree->has_children(node))
462 template<
class Writer>
463 void Emitter<Writer>::_blck_write_qmrk(
id_type node, csubstr
key,
type_bits ty,
bool has_qmrk_comments)
468 (void)has_qmrk_comments;
474 template<
class Writer>
475 void Emitter<Writer>::_blck_map_open_entry(
id_type node)
477 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_key(node), m_tree, node);
478 NodeType ty = m_tree->type(node);
479 csubstr
key = m_tree->key(node);
482 _write_pws_and_pend(_PWS_NONE);
485 _write_pws_and_pend(_PWS_SPACE);
487 _write(m_tree->key_anchor(node));
491 _write_pws_and_pend(_PWS_SPACE);
492 _write_tag(m_tree->key_tag(node));
496 _write_pws_and_pend(_PWS_SPACE);
501 _write_pws_and_pend(_PWS_NONE);
514 _write_pws_and_pend(_PWS_SPACE);
518 _write_pws_and_pend(_PWS_SPACE);
520 _write(m_tree->val_anchor(node));
524 _write_pws_and_pend(_PWS_SPACE);
525 _write_tag(m_tree->val_tag(node));
527 if(ty.is_container() && m_tree->has_children(node))
539 template<
class Writer>
540 void Emitter<Writer>::_blck_close_entry(
id_type node)
549 template<
class Writer>
550 void Emitter<Writer>::_visit_blck_seq(
id_type node)
552 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
554 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
557 NodeType ty = m_tree->type(child);
558 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
559 _blck_seq_open_entry(child);
562 _write_pws_and_pend(_PWS_NONE);
563 csubstr val = m_tree->val(child);
575 else if(ty.is_container())
579 _visit_blck_container(child);
583 _blck_close_entry(child);
587 _write_pws_and_pend(_PWS_NONE);
595 template<
class Writer>
596 void Emitter<Writer>::_visit_blck_map(
id_type node)
598 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
600 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
603 NodeType ty = m_tree->type(child);
604 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_keyval() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
605 _blck_map_open_entry(child);
608 _write_pws_and_pend(_PWS_NONE);
609 csubstr val = m_tree->val(child);
621 else if(ty.is_container())
625 _visit_blck_container(child);
629 _blck_close_entry(child);
633 _write_pws_and_pend(_PWS_NONE);
641 template<
class Writer>
642 void Emitter<Writer>::_visit_flow_sl_seq(
id_type node)
644 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
646 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
648 NodeType ty = m_tree->type(child);
649 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
650 _flow_seq_open_entry(child);
653 _write_pws_and_pend(_PWS_NONE);
654 csubstr val = m_tree->val(child);
659 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
666 else if(ty.is_container())
669 _visit_flow_container(child);
672 _flow_close_entry_sl(child, last);
680 template<
class Writer>
681 void Emitter<Writer>::_visit_flow_ml_seq(
id_type node)
683 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
686 if(m_opts.indent_flow_ml()) ++m_ilevel;
687 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
689 NodeType ty = m_tree->type(child);
690 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
691 _flow_seq_open_entry(child);
694 _write_pws_and_pend(_PWS_NONE);
695 csubstr val = m_tree->val(child);
700 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
707 else if(ty.is_container())
710 _visit_flow_container(child);
713 _flow_close_entry_ml(child, last);
715 if(m_opts.indent_flow_ml()) --m_ilevel;
716 _write_pws_and_pend(_PWS_NONE);
723 template<
class Writer>
724 void Emitter<Writer>::_visit_flow_sl_map(
id_type node)
726 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
728 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
730 NodeType ty = m_tree->type(child);
731 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty ==
NOTYPE), m_tree, node);
732 _flow_map_open_entry(child);
735 _write_pws_and_pend(_PWS_NONE);
736 csubstr val = m_tree->val(child);
741 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
748 else if(ty.is_container())
751 _visit_flow_container(child);
754 _flow_close_entry_sl(child, last);
756 _write_pws_and_pend(_PWS_NONE);
763 template<
class Writer>
764 void Emitter<Writer>::_visit_flow_ml_map(
id_type node)
766 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
769 if(m_opts.indent_flow_ml()) ++m_ilevel;
770 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
772 NodeType ty = m_tree->type(child);
773 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty ==
NOTYPE), m_tree, node);
774 _flow_map_open_entry(child);
777 _write_pws_and_pend(_PWS_NONE);
778 csubstr val = m_tree->val(child);
783 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
790 else if(ty.is_container())
793 _visit_flow_container(child);
796 _flow_close_entry_ml(child, last);
798 if(m_opts.indent_flow_ml()) --m_ilevel;
799 _write_pws_and_pend(_PWS_NONE);
806 template<
class Writer>
807 void Emitter<Writer>::_visit_blck(
id_type node)
809 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
810 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
811 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
812 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
813 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
814 const NodeType ty = m_tree->type(node);
817 _visit_blck_seq(node);
821 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
822 _visit_blck_map(node);
829 template<
class Writer>
830 void Emitter<Writer>::_visit_flow_sl(
id_type node)
832 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
833 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
834 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
835 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
836 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
837 const NodeType ty = m_tree->type(node);
840 _visit_flow_sl_seq(node);
844 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
845 _visit_flow_sl_map(node);
852 template<
class Writer>
853 void Emitter<Writer>::_visit_flow_ml(
id_type node)
855 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
856 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
857 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)), m_tree, node);
858 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
859 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
860 const NodeType ty = m_tree->type(node);
863 _visit_flow_ml_seq(node);
867 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
868 _visit_flow_ml_map(node);
875 template<
class Writer>
876 void Emitter<Writer>::_flow_write_scalar(csubstr str,
type_bits ty)
878 _RYML_ASSERT_BASIC_(m_tree->callbacks(), !(ty & _styles_block));
881 _write_scalar_plain(str, m_ilevel);
883 else if(ty & _styles_squo)
885 _write_scalar_squo(str, m_ilevel);
889 _write_scalar_dquo(str, m_ilevel);
893 template<
class Writer>
894 void Emitter<Writer>::_blck_write_scalar(csubstr str,
type_bits ty)
898 _write_scalar_plain(str, m_ilevel);
900 else if(ty & _styles_squo)
902 _write_scalar_squo(str, m_ilevel);
904 else if(ty & _styles_dquo)
906 _write_scalar_dquo(str, m_ilevel);
908 else if(ty & _styles_literal)
910 _write_scalar_literal(str, m_ilevel);
914 _write_scalar_folded(str, m_ilevel);
918 template<
class Writer>
919 size_t Emitter<Writer>::_write_escaped_newlines(csubstr s,
size_t i)
921 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.len > i);
922 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
'\n');
931 }
while(i < s.len && s.str[i] ==
'\n');
932 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
934 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
'\n');
939 inline bool _is_indented_block(csubstr s,
size_t prev,
size_t i) noexcept
941 if(prev == 0 && s.begins_with_any(
" \t"))
943 const size_t pos = s.first_not_of(
'\n', i);
944 return (pos !=
npos) && (s.str[pos] ==
' ' || s.str[pos] ==
'\t');
948 template<
class Writer>
949 size_t Emitter<Writer>::_write_indented_block(csubstr s,
size_t i,
id_type ilevel)
952 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
953 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i-1] ==
'\n');
954 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i < s.len);
955 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
' ' || s.str[i] ==
'\t' || s.str[i] ==
'\n');
957 size_t pos = s.find(
"\n ", i);
959 pos = s.find(
"\n\t", i);
965 _write(s.range(i, pos));
971 pos = s.find(
'\n', i);
974 const size_t pos2 = s.first_not_of(
'\n', pos);
975 pos = (pos2 !=
npos) ? pos2 : pos;
978 _write(s.range(i, pos));
984 template<
class Writer>
985 void Emitter<Writer>::_write_scalar_literal(csubstr s,
id_type ilevel)
987 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
988 csubstr trimmed = s.trimr(
'\n');
989 const size_t numnewlines_at_end = s.len - trimmed.len;
990 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
991 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
994 if(explicit_indentation)
997 if(numnewlines_at_end > 1 || is_newline_only)
999 else if(numnewlines_at_end == 0)
1006 for(
size_t i = 0; i < trimmed.len; ++i)
1008 if(trimmed[i] !=
'\n')
1011 csubstr since_pos = trimmed.range(pos, i+1);
1012 _indent(ilevel + 1);
1016 if(pos < trimmed.len)
1018 _indent(ilevel + 1);
1019 _write(trimmed.sub(pos));
1022 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1026 template<
class Writer>
1027 void Emitter<Writer>::_write_scalar_folded(csubstr s,
id_type ilevel)
1029 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
1030 csubstr trimmed = s.trimr(
'\n');
1031 const size_t numnewlines_at_end = s.len - trimmed.len;
1032 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
1033 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
1036 if(explicit_indentation)
1039 if(numnewlines_at_end == 0)
1041 else if(numnewlines_at_end > 1 || is_newline_only)
1048 for(
size_t i = 0; i < trimmed.len; ++i)
1050 if(trimmed[i] !=
'\n')
1053 if( ! _is_indented_block(s, pos, i))
1057 _indent(ilevel + 1);
1058 _write(s.range(pos, i));
1059 i = _write_escaped_newlines(s, i);
1066 if(s.str[i+1] ==
'\n')
1069 i = _write_escaped_newlines(s, i);
1083 _indent(ilevel + 1);
1084 _write(s.range(pos, i));
1085 if(pos > 0 || !s.begins_with_any(
" \t"))
1086 i = _write_indented_block(s, i, ilevel);
1090 if(pos < trimmed.len)
1092 _indent(ilevel + 1);
1093 _write(trimmed.sub(pos));
1096 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1100 template<
class Writer>
1101 void Emitter<Writer>::_write_scalar_squo(csubstr s,
id_type ilevel)
1105 for(
size_t i = 0; i < s.len; ++i)
1109 _write(s.range(pos, i));
1111 i = _write_escaped_newlines(s, i);
1114 _indent(ilevel + 1);
1117 else if(s[i] ==
'\'')
1119 csubstr sub = s.range(pos, i+1);
1132 template<
class Writer>
1133 void Emitter<Writer>::_write_scalar_dquo(csubstr s,
id_type ilevel)
1137 for(
size_t i = 0; i < s.len; ++i)
1139 const char curr = s.str[i];
1145 csubstr sub = s.range(pos, i);
1152 #ifndef prefer_writing_newlines_as_double_newlines
1155 csubstr sub = s.range(pos, i);
1167 _write(s.range(pos, i));
1168 i = _write_escaped_newlines(s, i);
1174 _indent(ilevel + 1);
1176 size_t first = s.first_not_of(
" \t", i);
1183 _write(s.range(i, first));
1195 const size_t next = s.first_not_of(
" \t\r", i);
1196 if(next !=
npos && s.str[next] ==
'\n')
1198 csubstr sub = s.range(pos, i);
1208 csubstr sub = s.range(pos, i);
1216 csubstr sub = s.range(pos, i);
1230 template<
class Writer>
1231 void Emitter<Writer>::_write_scalar_plain(csubstr s,
id_type ilevel)
1233 if(C4_UNLIKELY(ilevel == 0 && (s.begins_with(
"...") || s.begins_with(
"---"))))
1235 _indent(ilevel + 1);
1239 for(
size_t i = 0; i < s.len; ++i)
1241 const char curr = s.str[i];
1244 csubstr sub = s.range(pos, i);
1246 i = _write_escaped_newlines(s, i);
1249 _indent(ilevel + 1);
1260 template<
class Writer>
1261 void Emitter<Writer>::_json_emit(
id_type id)
1263 NodeType ty = m_tree->type(
id);
1266 _json_visit_sl(
id, 0);
1270 _json_visit_ml(
id, 0);
1275 template<
class Writer>
1278 _RYML_CHECK_VISIT_(m_tree->callbacks(), !m_tree->is_stream(
id), m_tree,
id);
1279 if(C4_UNLIKELY(depth > m_opts.max_depth()))
1280 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1281 NodeType ty = m_tree->type(
id);
1284 _json_writek(
id, ty);
1286 _json_writev(
id, ty);
1288 else if(ty.is_val())
1290 _json_writev(
id, ty);
1292 else if(ty.is_container())
1296 _json_writek(
id, ty);
1301 else if(ty.is_map())
1305 for(
id_type child = m_tree->first_child(
id); child !=
NONE; child = m_tree->next_sibling(child))
1307 if(child != m_tree->first_child(
id))
1309 _json_visit_sl(child, depth+1);
1314 else if(ty.is_map())
1318 template<
class Writer>
1321 _RYML_CHECK_VISIT_(m_tree->callbacks(), !m_tree->is_stream(
id), m_tree,
id);
1322 if(C4_UNLIKELY(depth > m_opts.max_depth()))
1323 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1324 NodeType ty = m_tree->type(
id);
1327 _json_writek(
id, ty);
1329 _json_writev(
id, ty);
1331 else if(ty.is_val())
1333 _json_writev(
id, ty);
1335 else if(ty.is_container())
1339 _json_writek(
id, ty);
1344 else if(ty.is_map())
1348 if(m_tree->has_children(
id))
1351 if(m_opts.indent_flow_ml()) ++m_ilevel;
1352 const id_type first = m_tree->first_child(
id);
1353 const id_type last = m_tree->last_child(
id);
1354 for(
id_type child = first; child !=
NONE; child = m_tree->next_sibling(child))
1358 NodeType chty = m_tree->type(child);
1360 _json_visit_sl(child, depth);
1362 _json_visit_ml(child, depth);
1366 if(m_opts.indent_flow_ml()) --m_ilevel;
1374 else if(ty.is_map())
1378 template<
class Writer>
1379 bool Emitter<Writer>::_json_maybe_write_naninf(csubstr s)
1381 if(s ==
"nan" || s ==
".nan" || s ==
".NaN" || s ==
".NAN")
1386 else if(s ==
"inf" || s ==
".inf" || s ==
".Inf" || s ==
".INF" || s ==
"infinity")
1391 else if(s ==
"-inf" || s ==
"-.inf" || s ==
"-.Inf" || s ==
"-.INF" || s ==
"-infinity")
1393 _write(
"\"-.inf\"");
1399 template<
class Writer>
1400 void Emitter<Writer>::_json_writek(
id_type id, NodeType ty)
1402 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG)
1403 if(C4_UNLIKELY(ty.has_key_tag()))
1404 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1405 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR)
1406 if(C4_UNLIKELY(ty.has_key_anchor()))
1407 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1408 csubstr
key = m_tree->key(
id);
1411 if(_json_maybe_write_naninf(
key))
1414 _json_write_scalar_dquo(
key);
1422 template<
class Writer>
1423 void Emitter<Writer>::_json_writev(
id_type id, NodeType ty)
1425 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG)
1426 if(C4_UNLIKELY(ty.has_val_tag()))
1427 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1428 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR)
1429 if(C4_UNLIKELY(ty.has_val_anchor()))
1430 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1431 csubstr val = m_tree->val(
id);
1435 bool dquoted = ((ty &
VALQUO)
1438 _json_write_scalar_dquo(val);
1439 else if(_json_maybe_write_naninf(val))
1441 else if(val.is_number())
1442 _json_write_number(val);
1456 template<
class Writer>
1457 void Emitter<Writer>::_json_write_scalar_dquo(csubstr s)
1461 for(
size_t i = 0; i < s.len; ++i)
1466 _write(s.range(pos, i));
1471 _write(s.range(pos, i));
1476 _write(s.range(pos, i));
1481 _write(s.range(pos, i));
1486 _write(s.range(pos, i));
1491 _write(s.range(pos, i));
1496 _write(s.range(pos, i));
1504 csubstr sub = s.sub(pos);
1510 template<
class Writer>
1511 void Emitter<Writer>::_json_write_number(csubstr s)
1519 if(s.begins_with(
'-') && s.len > 1)
1521 csubstr rest = s.sub(1);
1522 if(rest.begins_with(
'.'))
1527 else if(rest.ends_with(
'.'))
1537 else if(s.begins_with(
'.'))
1542 else if(s.ends_with(
'.'))
1560 C4_SUPPRESS_WARNING_GCC_CLANG_POP
A stateful emitter, for use with a writer such as WriterBuf, WriterFile, or WriterOStream.
id_type root_id() const
Get the id of the root node. The tree must not be empty.
Callbacks const & callbacks() const
Utilities to emit YAML and JSON.
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
NodeType_e
a bit mask for marking node types and styles
@ VALANCH
the val has an &anchor
@ NOTYPE
no node type or style is set
@ VALNIL
the val is null (eg {a : } results in a null val)
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ KEYTAG
the key has a tag
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
@ VALTAG
the val has a tag
@ 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)
@ KEYREF
a *reference: the key references an &anchor
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
@ KEYANCH
the key has an &anchor
@ VALQUO
val style is one of ', ", > or |
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
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
wraps a NodeType_e element with some syntactic sugar and predicates
bool has_key() const noexcept
bool is_doc() const noexcept
bool is_val_plain() const noexcept
bool is_flow_ml() const noexcept
bool has_val() const noexcept
bool is_container() const noexcept
bool is_val() const noexcept
bool is_stream() const noexcept