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")
18 template<
class Writer>
39 _RYML_ERR_BASIC_(m_tree->callbacks(),
"unknown emit type");
41 return this->Writer::_get(error_on_excess);
59 template<
class Writer>
65 const bool has_parent = !m_tree->is_root(
id);
66 const bool emit_key = has_parent && ty.
has_key() && m_opts.emit_nonroot_key();
67 const bool emit_dash = has_parent && !ty.
has_key() && !ty.
is_doc() && m_opts.emit_nonroot_dash();
68 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !(emit_key && emit_dash), m_tree,
id);
73 _blck_map_open_entry(
id);
78 _blck_seq_open_entry(
id);
89 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
94 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_ilevel == 0, m_tree,
id);
99 _visit_blck_container(
id);
110 _blck_close_entry(
id);
115 _blck_close_entry(
id);
119 _top_close_entry(
id);
126 else if(m_tree->is_root(
id)
127 || emit_dash || emit_key
131 _write_pws_and_pend(_PWS_NONE);
138 template<
class Writer>
139 void Emitter<Writer>::_visit_stream(
id_type id)
141 TagDirectiveRange tagds = m_tree->tag_directives();
142 auto write_tag_directives = [&tagds,
this](
const id_type next_node){
143 TagDirective
const* C4_RESTRICT end = tagds.b;
146 if(end->next_node_id > next_node)
150 const id_type parent = m_tree->parent(next_node);
151 for( ; tagds.b != end; ++tagds.b)
153 if(next_node != m_tree->first_child(parent))
155 _write_pws_and_pend(_PWS_NEWL);
158 _write_pws_and_pend(_PWS_NONE);
160 _write(tagds.b->handle);
162 _write(tagds.b->prefix);
166 const id_type first_child = m_tree->first_child(
id);
167 if(first_child !=
NONE)
168 write_tag_directives(first_child);
170 for(
id_type child = first_child; child !=
NONE; child = m_tree->next_sibling(child))
173 _write_pws_and_pend(_PWS_NONE);
174 _top_open_entry(child);
176 _top_close_entry(child);
177 if(m_tree->is_val(child))
179 if(m_tree->type(child) &
VALNIL)
182 else if(m_tree->is_container(child))
184 if(m_tree->is_flow(child))
187 if(m_tree->next_sibling(child) !=
NONE)
189 write_tag_directives(m_tree->next_sibling(child));
198 template<
class Writer>
199 void Emitter<Writer>::_visit_blck_container(
id_type id)
201 NodeType ty = m_tree->
type(
id);
204 _write_pws_and_pend(_PWS_NONE);
207 else if(ty.is_flow_ml())
213 template<
class Writer>
214 void Emitter<Writer>::_visit_flow_container(
id_type id)
216 NodeType ty = m_tree->type(
id);
219 _write_pws_and_pend(_PWS_NONE);
229 template<
class Writer>
230 void Emitter<Writer>::_visit_doc_val(
id_type id)
234 NodeType ty = m_tree->type(
id);
235 const csubstr val = m_tree->val(
id);
237 const bool is_ambiguous = ((ty &
VAL_PLAIN) || !val_style)
238 && (val.begins_with(
"...") || val.begins_with(
"---"));
242 if(m_pws != _PWS_NONE)
247 _write_pws_and_pend(_PWS_NONE);
248 if(m_tree->is_val_ref(
id))
256 _blck_write_scalar(val, val_style);
267 template<
class Writer>
268 void Emitter<Writer>::_visit_doc(
id_type id)
270 const NodeType ty = m_tree->type(
id);
271 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ty.is_doc(), m_tree,
id);
272 _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !ty.has_key(), m_tree,
id);
273 if(ty.is_container())
275 _visit_blck_container(
id);
287 template<
class Writer>
288 void Emitter<Writer>::_top_open_entry(
id_type node)
290 NodeType ty = m_tree->type(node);
291 if(ty.is_doc() && !m_tree->is_root(node))
296 if(ty.has_val_anchor())
298 _write_pws_and_pend(_PWS_SPACE);
300 _write(m_tree->val_anchor(node));
304 _write_pws_and_pend(_PWS_SPACE);
305 _write_tag(m_tree->val_tag(node));
307 if(m_pws == _PWS_SPACE)
311 if(ty.is_val_plain() && !m_tree->val(node).len)
316 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_container(), m_tree, node);
326 template<
class Writer>
327 void Emitter<Writer>::_top_close_entry(
id_type node)
329 if(m_tree->is_val(node) && !(m_tree->type(node) &
VALNIL))
338 template<
class Writer>
339 void Emitter<Writer>::_flow_seq_open_entry(
id_type node)
341 NodeType ty = m_tree->type(node);
342 _write_pws_and_pend(_PWS_NONE);
345 _write_pws_and_pend(_PWS_SPACE);
347 _write(m_tree->val_anchor(node));
351 _write_pws_and_pend(_PWS_SPACE);
352 _write_tag(m_tree->val_tag(node));
359 template<
class Writer>
360 void Emitter<Writer>::_flow_map_open_entry(
id_type node)
362 NodeType ty = m_tree->type(node);
363 _write_pws_and_pend(_PWS_NONE);
364 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key(), m_tree, node);
367 _write_pws_and_pend(_PWS_SPACE);
369 _write(m_tree->key_anchor(node));
373 _write_pws_and_pend(_PWS_SPACE);
374 _write_tag(m_tree->key_tag(node));
378 _write_pws_and_pend(_PWS_SPACE);
379 _write_ref(m_tree->key(node));
383 _write_pws_and_pend(_PWS_NONE);
384 csubstr
key = m_tree->key(node);
389 _write_pws_and_pend(_PWS_SPACE);
393 _write_pws_and_pend(_PWS_SPACE);
395 _write(m_tree->val_anchor(node));
399 _write_pws_and_pend(_PWS_SPACE);
400 _write_tag(m_tree->val_tag(node));
407 template<
class Writer>
408 void Emitter<Writer>::_flow_close_entry_sl(
id_type node,
id_type last_sibling)
410 if(node != last_sibling)
412 _write_pws_and_pend(_PWS_NONE);
417 template<
class Writer>
418 void Emitter<Writer>::_flow_close_entry_ml(
id_type node,
id_type last_sibling)
420 if(node != last_sibling)
422 _write_pws_and_pend(_PWS_NONE);
431 template<
class Writer>
432 void Emitter<Writer>::_blck_seq_open_entry(
id_type node)
434 NodeType ty = m_tree->type(node);
435 _write_pws_and_pend(_PWS_NONE);
436 _write_pws_and_pend(_PWS_SPACE);
438 bool has_tag_or_anchor =
false;
441 has_tag_or_anchor =
true;
442 _write_pws_and_pend(_PWS_SPACE);
444 _write(m_tree->val_anchor(node));
448 has_tag_or_anchor =
true;
449 _write_pws_and_pend(_PWS_SPACE);
450 _write_tag(m_tree->val_tag(node));
452 if(has_tag_or_anchor && ty.is_container())
456 if((ty &
BLOCK) && m_tree->has_children(node))
464 template<
class Writer>
465 void Emitter<Writer>::_blck_write_qmrk(
id_type node, csubstr
key,
type_bits ty,
bool has_qmrk_comments)
470 (void)has_qmrk_comments;
476 template<
class Writer>
477 void Emitter<Writer>::_blck_map_open_entry(
id_type node)
479 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_key(node), m_tree, node);
480 NodeType ty = m_tree->type(node);
481 csubstr
key = m_tree->key(node);
484 _write_pws_and_pend(_PWS_NONE);
487 _write_pws_and_pend(_PWS_SPACE);
489 _write(m_tree->key_anchor(node));
493 _write_pws_and_pend(_PWS_SPACE);
494 _write_tag(m_tree->key_tag(node));
498 _write_pws_and_pend(_PWS_SPACE);
503 _write_pws_and_pend(_PWS_NONE);
516 _write_pws_and_pend(_PWS_SPACE);
520 _write_pws_and_pend(_PWS_SPACE);
522 _write(m_tree->val_anchor(node));
526 _write_pws_and_pend(_PWS_SPACE);
527 _write_tag(m_tree->val_tag(node));
529 if(ty.is_container() && m_tree->has_children(node))
541 template<
class Writer>
542 void Emitter<Writer>::_blck_close_entry(
id_type node)
551 template<
class Writer>
552 void Emitter<Writer>::_visit_blck_seq(
id_type node)
554 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
556 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
559 NodeType ty = m_tree->type(child);
560 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
561 _blck_seq_open_entry(child);
564 _write_pws_and_pend(_PWS_NONE);
565 csubstr val = m_tree->val(child);
577 else if(ty.is_container())
581 _visit_blck_container(child);
585 _blck_close_entry(child);
589 _write_pws_and_pend(_PWS_NONE);
597 template<
class Writer>
598 void Emitter<Writer>::_visit_blck_map(
id_type node)
600 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
602 for(
id_type child = m_tree->first_child(node); child !=
NONE; child = m_tree->next_sibling(child))
605 NodeType ty = m_tree->type(child);
606 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_keyval() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
607 _blck_map_open_entry(child);
610 _write_pws_and_pend(_PWS_NONE);
611 csubstr val = m_tree->val(child);
623 else if(ty.is_container())
627 _visit_blck_container(child);
631 _blck_close_entry(child);
635 _write_pws_and_pend(_PWS_NONE);
643 template<
class Writer>
644 void Emitter<Writer>::_visit_flow_sl_seq(
id_type node)
646 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
648 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
650 NodeType ty = m_tree->type(child);
651 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
652 _flow_seq_open_entry(child);
655 _write_pws_and_pend(_PWS_NONE);
656 csubstr val = m_tree->val(child);
661 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
668 else if(ty.is_container())
671 _visit_flow_container(child);
674 _flow_close_entry_sl(child, last);
682 template<
class Writer>
683 void Emitter<Writer>::_visit_flow_ml_seq(
id_type node)
685 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
688 if(m_opts.indent_flow_ml()) ++m_ilevel;
689 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
691 NodeType ty = m_tree->type(child);
692 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty ==
NOTYPE, m_tree, node);
693 _flow_seq_open_entry(child);
696 _write_pws_and_pend(_PWS_NONE);
697 csubstr val = m_tree->val(child);
702 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
709 else if(ty.is_container())
712 _visit_flow_container(child);
715 _flow_close_entry_ml(child, last);
717 if(m_opts.indent_flow_ml()) --m_ilevel;
718 _write_pws_and_pend(_PWS_NONE);
725 template<
class Writer>
726 void Emitter<Writer>::_visit_flow_sl_map(
id_type node)
728 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
730 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
732 NodeType ty = m_tree->type(child);
733 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty ==
NOTYPE), m_tree, node);
734 _flow_map_open_entry(child);
737 _write_pws_and_pend(_PWS_NONE);
738 csubstr val = m_tree->val(child);
743 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
750 else if(ty.is_container())
753 _visit_flow_container(child);
756 _flow_close_entry_sl(child, last);
758 _write_pws_and_pend(_PWS_NONE);
765 template<
class Writer>
766 void Emitter<Writer>::_visit_flow_ml_map(
id_type node)
768 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
771 if(m_opts.indent_flow_ml()) ++m_ilevel;
772 for(
id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child !=
NONE; child = m_tree->next_sibling(child))
774 NodeType ty = m_tree->type(child);
775 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty ==
NOTYPE), m_tree, node);
776 _flow_map_open_entry(child);
779 _write_pws_and_pend(_PWS_NONE);
780 csubstr val = m_tree->val(child);
785 _flow_write_scalar(val, ty & (
NodeType_e)_styles_flow_val);
792 else if(ty.is_container())
795 _visit_flow_container(child);
798 _flow_close_entry_ml(child, last);
800 if(m_opts.indent_flow_ml()) --m_ilevel;
801 _write_pws_and_pend(_PWS_NONE);
808 template<
class Writer>
809 void Emitter<Writer>::_visit_blck(
id_type node)
811 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
812 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
813 _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);
814 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
815 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
816 const NodeType ty = m_tree->type(node);
819 _visit_blck_seq(node);
823 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
824 _visit_blck_map(node);
831 template<
class Writer>
832 void Emitter<Writer>::_visit_flow_sl(
id_type node)
834 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
835 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
836 _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);
837 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
838 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
839 const NodeType ty = m_tree->type(node);
842 _visit_flow_sl_seq(node);
846 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
847 _visit_flow_sl_map(node);
854 template<
class Writer>
855 void Emitter<Writer>::_visit_flow_ml(
id_type node)
857 _RYML_ASSERT_VISIT_(m_tree->callbacks(), !m_tree->is_stream(node), m_tree, node);
858 _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_container(node) || m_tree->is_doc(node), m_tree, node);
859 _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);
860 if(C4_UNLIKELY(m_depth > m_opts.max_depth()))
861 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node,
"max depth exceeded");
862 const NodeType ty = m_tree->type(node);
865 _visit_flow_ml_seq(node);
869 _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_map(), m_tree, node);
870 _visit_flow_ml_map(node);
877 template<
class Writer>
878 void Emitter<Writer>::_flow_write_scalar(csubstr str,
type_bits ty)
880 _RYML_ASSERT_BASIC_(m_tree->callbacks(), !(ty & _styles_block));
883 _write_scalar_plain(str, m_ilevel);
885 else if(ty & _styles_squo)
887 _write_scalar_squo(str, m_ilevel);
891 _write_scalar_dquo(str, m_ilevel);
895 template<
class Writer>
896 void Emitter<Writer>::_blck_write_scalar(csubstr str,
type_bits ty)
900 _write_scalar_plain(str, m_ilevel);
902 else if(ty & _styles_squo)
904 _write_scalar_squo(str, m_ilevel);
906 else if(ty & _styles_dquo)
908 _write_scalar_dquo(str, m_ilevel);
910 else if(ty & _styles_literal)
912 _write_scalar_literal(str, m_ilevel);
916 _write_scalar_folded(str, m_ilevel);
920 template<
class Writer>
921 size_t Emitter<Writer>::_write_escaped_newlines(csubstr s,
size_t i)
923 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.len > i);
924 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
'\n');
933 }
while(i < s.len && s.str[i] ==
'\n');
934 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
936 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
'\n');
941 inline bool _is_indented_block(csubstr s,
size_t prev,
size_t i) noexcept
943 if(prev == 0 && s.begins_with_any(
" \t"))
945 const size_t pos = s.first_not_of(
'\n', i);
946 return (pos !=
npos) && (s.str[pos] ==
' ' || s.str[pos] ==
'\t');
950 template<
class Writer>
951 size_t Emitter<Writer>::_write_indented_block(csubstr s,
size_t i,
id_type ilevel)
954 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i > 0);
955 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i-1] ==
'\n');
956 _RYML_ASSERT_BASIC_(m_tree->callbacks(), i < s.len);
957 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.str[i] ==
' ' || s.str[i] ==
'\t' || s.str[i] ==
'\n');
959 size_t pos = s.find(
"\n ", i);
961 pos = s.find(
"\n\t", i);
967 _write(s.range(i, pos));
973 pos = s.find(
'\n', i);
976 const size_t pos2 = s.first_not_of(
'\n', pos);
977 pos = (pos2 !=
npos) ? pos2 : pos;
980 _write(s.range(i, pos));
986 template<
class Writer>
987 void Emitter<Writer>::_write_scalar_literal(csubstr s,
id_type ilevel)
989 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
990 csubstr trimmed = s.trimr(
'\n');
991 const size_t numnewlines_at_end = s.len - trimmed.len;
992 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
993 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
996 if(explicit_indentation)
999 if(numnewlines_at_end > 1 || is_newline_only)
1001 else if(numnewlines_at_end == 0)
1008 for(
size_t i = 0; i < trimmed.len; ++i)
1010 if(trimmed[i] !=
'\n')
1013 csubstr since_pos = trimmed.range(pos, i+1);
1014 _indent(ilevel + 1);
1018 if(pos < trimmed.len)
1020 _indent(ilevel + 1);
1021 _write(trimmed.sub(pos));
1024 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1028 template<
class Writer>
1029 void Emitter<Writer>::_write_scalar_folded(csubstr s,
id_type ilevel)
1031 _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find(
"\r") ==
csubstr::npos);
1032 csubstr trimmed = s.trimr(
'\n');
1033 const size_t numnewlines_at_end = s.len - trimmed.len;
1034 const bool is_newline_only = (trimmed.len == 0 && (s.len > 0));
1035 const bool explicit_indentation = s.triml(
"\n\r").begins_with_any(
" \t");
1038 if(explicit_indentation)
1041 if(numnewlines_at_end == 0)
1043 else if(numnewlines_at_end > 1 || is_newline_only)
1050 for(
size_t i = 0; i < trimmed.len; ++i)
1052 if(trimmed[i] !=
'\n')
1055 if( ! _is_indented_block(s, pos, i))
1059 _indent(ilevel + 1);
1060 _write(s.range(pos, i));
1061 i = _write_escaped_newlines(s, i);
1068 if(s.str[i+1] ==
'\n')
1071 i = _write_escaped_newlines(s, i);
1085 _indent(ilevel + 1);
1086 _write(s.range(pos, i));
1087 if(pos > 0 || !s.begins_with_any(
" \t"))
1088 i = _write_indented_block(s, i, ilevel);
1092 if(pos < trimmed.len)
1094 _indent(ilevel + 1);
1095 _write(trimmed.sub(pos));
1098 for(
size_t i = !is_newline_only; i < numnewlines_at_end; ++i)
1102 template<
class Writer>
1103 void Emitter<Writer>::_write_scalar_squo(csubstr s,
id_type ilevel)
1107 for(
size_t i = 0; i < s.len; ++i)
1111 _write(s.range(pos, i));
1113 i = _write_escaped_newlines(s, i);
1116 _indent(ilevel + 1);
1119 else if(s[i] ==
'\'')
1121 csubstr sub = s.range(pos, i+1);
1134 template<
class Writer>
1135 void Emitter<Writer>::_write_scalar_dquo(csubstr s,
id_type ilevel)
1139 for(
size_t i = 0; i < s.len; ++i)
1141 const char curr = s.str[i];
1147 csubstr sub = s.range(pos, i);
1154 #ifndef prefer_writing_newlines_as_double_newlines
1157 csubstr sub = s.range(pos, i);
1169 _write(s.range(pos, i));
1170 i = _write_escaped_newlines(s, i);
1176 _indent(ilevel + 1);
1178 size_t first = s.first_not_of(
" \t", i);
1185 _write(s.range(i, first));
1197 const size_t next = s.first_not_of(
" \t\r", i);
1198 if(next !=
npos && s.str[next] ==
'\n')
1200 csubstr sub = s.range(pos, i);
1210 csubstr sub = s.range(pos, i);
1218 csubstr sub = s.range(pos, i);
1232 template<
class Writer>
1233 void Emitter<Writer>::_write_scalar_plain(csubstr s,
id_type ilevel)
1235 if(C4_UNLIKELY(ilevel == 0 && (s.begins_with(
"...") || s.begins_with(
"---"))))
1237 _indent(ilevel + 1);
1241 for(
size_t i = 0; i < s.len; ++i)
1243 const char curr = s.str[i];
1246 csubstr sub = s.range(pos, i);
1248 i = _write_escaped_newlines(s, i);
1251 _indent(ilevel + 1);
1262 template<
class Writer>
1263 void Emitter<Writer>::_json_emit(
id_type id)
1265 NodeType ty = m_tree->type(
id);
1268 _json_visit_sl(
id, 0);
1272 _json_visit_ml(
id, 0);
1277 template<
class Writer>
1280 _RYML_CHECK_VISIT_(m_tree->callbacks(), !m_tree->is_stream(
id), m_tree,
id);
1281 if(C4_UNLIKELY(depth > m_opts.max_depth()))
1282 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1283 NodeType ty = m_tree->type(
id);
1286 _json_writek(
id, ty);
1288 _json_writev(
id, ty);
1290 else if(ty.is_val())
1292 _json_writev(
id, ty);
1294 else if(ty.is_container())
1298 _json_writek(
id, ty);
1303 else if(ty.is_map())
1307 for(
id_type child = m_tree->first_child(
id); child !=
NONE; child = m_tree->next_sibling(child))
1309 if(child != m_tree->first_child(
id))
1311 _json_visit_sl(child, depth+1);
1316 else if(ty.is_map())
1320 template<
class Writer>
1323 _RYML_CHECK_VISIT_(m_tree->callbacks(), !m_tree->is_stream(
id), m_tree,
id);
1324 if(C4_UNLIKELY(depth > m_opts.max_depth()))
1325 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"max depth exceeded");
1326 NodeType ty = m_tree->type(
id);
1329 _json_writek(
id, ty);
1331 _json_writev(
id, ty);
1333 else if(ty.is_val())
1335 _json_writev(
id, ty);
1337 else if(ty.is_container())
1341 _json_writek(
id, ty);
1346 else if(ty.is_map())
1350 if(m_tree->has_children(
id))
1353 if(m_opts.indent_flow_ml()) ++m_ilevel;
1354 const id_type first = m_tree->first_child(
id);
1355 const id_type last = m_tree->last_child(
id);
1356 for(
id_type child = first; child !=
NONE; child = m_tree->next_sibling(child))
1360 NodeType chty = m_tree->type(child);
1362 _json_visit_sl(child, depth);
1364 _json_visit_ml(child, depth);
1368 if(m_opts.indent_flow_ml()) --m_ilevel;
1376 else if(ty.is_map())
1380 template<
class Writer>
1381 bool Emitter<Writer>::_json_maybe_write_naninf(csubstr s)
1383 if(s ==
"nan" || s ==
".nan" || s ==
".NaN" || s ==
".NAN")
1388 else if(s ==
"inf" || s ==
".inf" || s ==
".Inf" || s ==
".INF" || s ==
"infinity")
1393 else if(s ==
"-inf" || s ==
"-.inf" || s ==
"-.Inf" || s ==
"-.INF" || s ==
"-infinity")
1395 _write(
"\"-.inf\"");
1401 template<
class Writer>
1402 void Emitter<Writer>::_json_writek(
id_type id, NodeType ty)
1404 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG)
1405 if(C4_UNLIKELY(ty.has_key_tag()))
1406 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1407 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR)
1408 if(C4_UNLIKELY(ty.has_key_anchor()))
1409 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1410 csubstr
key = m_tree->key(
id);
1413 if(_json_maybe_write_naninf(
key))
1416 _json_write_scalar_dquo(
key);
1424 template<
class Writer>
1425 void Emitter<Writer>::_json_writev(
id_type id, NodeType ty)
1427 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_TAG)
1428 if(C4_UNLIKELY(ty.has_val_tag()))
1429 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have tags");
1430 if(m_opts.json_error_flags() & EmitOptions::JSON_ERR_ON_ANCHOR)
1431 if(C4_UNLIKELY(ty.has_val_anchor()))
1432 _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree,
id,
"JSON does not have anchors");
1433 csubstr val = m_tree->val(
id);
1437 bool dquoted = ((ty &
VALQUO)
1440 _json_write_scalar_dquo(val);
1441 else if(_json_maybe_write_naninf(val))
1443 else if(val.is_number())
1444 _json_write_number(val);
1458 template<
class Writer>
1459 void Emitter<Writer>::_json_write_scalar_dquo(csubstr s)
1463 for(
size_t i = 0; i < s.len; ++i)
1468 _write(s.range(pos, i));
1473 _write(s.range(pos, i));
1478 _write(s.range(pos, i));
1483 _write(s.range(pos, i));
1488 _write(s.range(pos, i));
1493 _write(s.range(pos, i));
1498 _write(s.range(pos, i));
1506 csubstr sub = s.sub(pos);
1512 template<
class Writer>
1513 void Emitter<Writer>::_json_write_number(csubstr s)
1521 if(s.begins_with(
'-') && s.len > 1)
1523 csubstr rest = s.sub(1);
1524 if(rest.begins_with(
'.'))
1529 else if(rest.ends_with(
'.'))
1539 else if(s.begins_with(
'.'))
1544 else if(s.ends_with(
'.'))
1561 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