diff options
Diffstat (limited to 'thirdparty/ryml/src/c4/yml/emit.def.hpp')
| -rw-r--r-- | thirdparty/ryml/src/c4/yml/emit.def.hpp | 960 |
1 files changed, 0 insertions, 960 deletions
diff --git a/thirdparty/ryml/src/c4/yml/emit.def.hpp b/thirdparty/ryml/src/c4/yml/emit.def.hpp deleted file mode 100644 index d262a9e2a..000000000 --- a/thirdparty/ryml/src/c4/yml/emit.def.hpp +++ /dev/null @@ -1,960 +0,0 @@ -#ifndef _C4_YML_EMIT_DEF_HPP_ -#define _C4_YML_EMIT_DEF_HPP_ - -#ifndef _C4_YML_EMIT_HPP_ -#include "c4/yml/emit.hpp" -#endif - -namespace c4 { -namespace yml { - -template<class Writer> -substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess) -{ - if(t.empty()) - { - _RYML_CB_ASSERT(t.callbacks(), id == NONE); - return {}; - } - _RYML_CB_CHECK(t.callbacks(), id < t.size()); - m_tree = &t; - if(type == EMIT_YAML) - _emit_yaml(id); - else if(type == EMIT_JSON) - _do_visit_json(id); - else - _RYML_CB_ERR(m_tree->callbacks(), "unknown emit type"); - return this->Writer::_get(error_on_excess); -} - -template<class Writer> -substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, bool error_on_excess) -{ - if(t.empty()) - return {}; - return this->emit_as(type, t, t.root_id(), error_on_excess); -} - -template<class Writer> -substr Emitter<Writer>::emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess) -{ - _RYML_CB_CHECK(n.tree()->callbacks(), n.valid()); - return this->emit_as(type, *n.tree(), n.id(), error_on_excess); -} - - -//----------------------------------------------------------------------------- - -template<class Writer> -void Emitter<Writer>::_emit_yaml(size_t id) -{ - // save branches in the visitor by doing the initial stream/doc - // logic here, sparing the need to check stream/val/keyval inside - // the visitor functions - auto dispatch = [this](size_t node){ - NodeType ty = m_tree->type(node); - if(ty.marked_flow_sl()) - _do_visit_flow_sl(node, 0); - else if(ty.marked_flow_ml()) - _do_visit_flow_ml(node, 0); - else - { - _do_visit_block(node, 0); - } - }; - if(!m_tree->is_root(id)) - { - if(m_tree->is_container(id) && !m_tree->type(id).marked_flow()) - { - size_t ilevel = 0; - if(m_tree->has_key(id)) - { - this->Writer::_do_write(m_tree->key(id)); - this->Writer::_do_write(":\n"); - ++ilevel; - } - _do_visit_block_container(id, ilevel, ilevel); - return; - } - } - - auto *btd = m_tree->tag_directives().b; - auto *etd = m_tree->tag_directives().e; - auto write_tag_directives = [&btd, etd, this](size_t next_node){ - auto end = btd; - while(end < etd) - { - if(end->next_node_id > next_node) - break; - ++end; - } - for( ; btd != end; ++btd) - { - if(next_node != m_tree->first_child(m_tree->parent(next_node))) - this->Writer::_do_write("...\n"); - this->Writer::_do_write("%TAG "); - this->Writer::_do_write(btd->handle); - this->Writer::_do_write(' '); - this->Writer::_do_write(btd->prefix); - this->Writer::_do_write('\n'); - } - }; - if(m_tree->is_stream(id)) - { - if(m_tree->first_child(id) != NONE) - write_tag_directives(m_tree->first_child(id)); - for(size_t child = m_tree->first_child(id); child != NONE; child = m_tree->next_sibling(child)) - { - dispatch(child); - if(m_tree->next_sibling(child) != NONE) - write_tag_directives(m_tree->next_sibling(child)); - } - } - else if(m_tree->is_container(id)) - { - dispatch(id); - } - else if(m_tree->is_doc(id)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_container(id)); // checked above - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_val(id)); // so it must be a val - _write_doc(id); - } - else if(m_tree->is_keyval(id)) - { - _writek(id, 0); - this->Writer::_do_write(": "); - _writev(id, 0); - if(!m_tree->type(id).marked_flow()) - this->Writer::_do_write('\n'); - } - else if(m_tree->is_val(id)) - { - //this->Writer::_do_write("- "); - _writev(id, 0); - if(!m_tree->type(id).marked_flow()) - this->Writer::_do_write('\n'); - } - else if(m_tree->type(id) == NOTYPE) - { - ; - } - else - { - _RYML_CB_ERR(m_tree->callbacks(), "unknown type"); - } -} - -template<class Writer> -void Emitter<Writer>::_write_doc(size_t id) -{ - RYML_ASSERT(m_tree->is_doc(id)); - if(!m_tree->is_root(id)) - { - RYML_ASSERT(m_tree->is_stream(m_tree->parent(id))); - this->Writer::_do_write("---"); - } - if(!m_tree->has_val(id)) // this is more frequent - { - if(m_tree->has_val_tag(id)) - { - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(id)); - } - if(m_tree->has_val_anchor(id)) - { - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(id)); - } - } - else // docval - { - RYML_ASSERT(m_tree->has_val(id)); - RYML_ASSERT(!m_tree->has_key(id)); - if(!m_tree->is_root(id)) - this->Writer::_do_write(' '); - _writev(id, 0); - } - this->Writer::_do_write('\n'); -} - -template<class Writer> -void Emitter<Writer>::_do_visit_flow_sl(size_t node, size_t ilevel) -{ - RYML_ASSERT(!m_tree->is_stream(node)); - RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node)); - RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node))); - - if(m_tree->is_doc(node)) - { - _write_doc(node); - if(!m_tree->has_children(node)) - return; - } - else if(m_tree->is_container(node)) - { - RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node)); - - bool spc = false; // write a space - - if(m_tree->has_key(node)) - { - _writek(node, ilevel); - this->Writer::_do_write(':'); - spc = true; - } - - if(m_tree->has_val_tag(node)) - { - if(spc) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(node)); - spc = true; - } - - if(m_tree->has_val_anchor(node)) - { - if(spc) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(node)); - spc = true; - } - - if(spc) - this->Writer::_do_write(' '); - - if(m_tree->is_map(node)) - { - this->Writer::_do_write('{'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node)); - this->Writer::_do_write('['); - } - } // container - - for(size_t child = m_tree->first_child(node), count = 0; child != NONE; child = m_tree->next_sibling(child)) - { - if(count++) - this->Writer::_do_write(','); - if(m_tree->is_keyval(child)) - { - _writek(child, ilevel); - this->Writer::_do_write(": "); - _writev(child, ilevel); - } - else if(m_tree->is_val(child)) - { - _writev(child, ilevel); - } - else - { - // with single-line flow, we can never go back to block - _do_visit_flow_sl(child, ilevel + 1); - } - } - - if(m_tree->is_map(node)) - { - this->Writer::_do_write('}'); - } - else if(m_tree->is_seq(node)) - { - this->Writer::_do_write(']'); - } -} - -template<class Writer> -void Emitter<Writer>::_do_visit_flow_ml(size_t id, size_t ilevel, size_t do_indent) -{ - C4_UNUSED(id); - C4_UNUSED(ilevel); - C4_UNUSED(do_indent); - RYML_CHECK(false/*not implemented*/); -} - -template<class Writer> -void Emitter<Writer>::_do_visit_block_container(size_t node, size_t next_level, size_t do_indent) -{ - RepC ind = indent_to(do_indent * next_level); - - if(m_tree->is_seq(node)) - { - for(size_t child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child)); - if(m_tree->is_val(child)) - { - this->Writer::_do_write(ind); - this->Writer::_do_write("- "); - _writev(child, next_level); - this->Writer::_do_write('\n'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child)); - NodeType ty = m_tree->type(child); - if(ty.marked_flow_sl()) - { - this->Writer::_do_write(ind); - this->Writer::_do_write("- "); - _do_visit_flow_sl(child, 0u); - this->Writer::_do_write('\n'); - } - else if(ty.marked_flow_ml()) - { - this->Writer::_do_write(ind); - this->Writer::_do_write("- "); - _do_visit_flow_ml(child, next_level, do_indent); - this->Writer::_do_write('\n'); - } - else - { - _do_visit_block(child, next_level, do_indent); - } - } - do_indent = true; - ind = indent_to(do_indent * next_level); - } - } - else // map - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node)); - for(size_t ich = m_tree->first_child(node); ich != NONE; ich = m_tree->next_sibling(ich)) - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich)); - if(m_tree->is_keyval(ich)) - { - this->Writer::_do_write(ind); - _writek(ich, next_level); - this->Writer::_do_write(": "); - _writev(ich, next_level); - this->Writer::_do_write('\n'); - } - else - { - _RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich)); - NodeType ty = m_tree->type(ich); - if(ty.marked_flow_sl()) - { - this->Writer::_do_write(ind); - _do_visit_flow_sl(ich, 0u); - this->Writer::_do_write('\n'); - } - else if(ty.marked_flow_ml()) - { - this->Writer::_do_write(ind); - _do_visit_flow_ml(ich, 0u); - this->Writer::_do_write('\n'); - } - else - { - _do_visit_block(ich, next_level, do_indent); - } - } - do_indent = true; - ind = indent_to(do_indent * next_level); - } - } -} - -template<class Writer> -void Emitter<Writer>::_do_visit_block(size_t node, size_t ilevel, size_t do_indent) -{ - RYML_ASSERT(!m_tree->is_stream(node)); - RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node)); - RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node))); - RepC ind = indent_to(do_indent * ilevel); - - if(m_tree->is_doc(node)) - { - _write_doc(node); - if(!m_tree->has_children(node)) - return; - } - else if(m_tree->is_container(node)) - { - RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node)); - - bool spc = false; // write a space - bool nl = false; // write a newline - - if(m_tree->has_key(node)) - { - this->Writer::_do_write(ind); - _writek(node, ilevel); - this->Writer::_do_write(':'); - spc = true; - } - else if(!m_tree->is_root(node)) - { - this->Writer::_do_write(ind); - this->Writer::_do_write('-'); - spc = true; - } - - if(m_tree->has_val_tag(node)) - { - if(spc) - this->Writer::_do_write(' '); - _write_tag(m_tree->val_tag(node)); - spc = true; - nl = true; - } - - if(m_tree->has_val_anchor(node)) - { - if(spc) - this->Writer::_do_write(' '); - this->Writer::_do_write('&'); - this->Writer::_do_write(m_tree->val_anchor(node)); - spc = true; - nl = true; - } - - if(m_tree->has_children(node)) - { - if(m_tree->has_key(node)) - nl = true; - else - if(!m_tree->is_root(node) && !nl) - spc = true; - } - else - { - if(m_tree->is_seq(node)) - this->Writer::_do_write(" []\n"); - else if(m_tree->is_map(node)) - this->Writer::_do_write(" {}\n"); - return; - } - - if(spc && !nl) - this->Writer::_do_write(' '); - - do_indent = 0; - if(nl) - { - this->Writer::_do_write('\n'); - do_indent = 1; - } - } // container - - size_t next_level = ilevel + 1; - if(m_tree->is_root(node) || m_tree->is_doc(node)) - next_level = ilevel; // do not indent at top level - - _do_visit_block_container(node, next_level, do_indent); -} - -template<class Writer> -void Emitter<Writer>::_do_visit_json(size_t id) -{ - _RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(id)); // JSON does not have streams - if(m_tree->is_keyval(id)) - { - _writek_json(id); - this->Writer::_do_write(": "); - _writev_json(id); - } - else if(m_tree->is_val(id)) - { - _writev_json(id); - } - else if(m_tree->is_container(id)) - { - if(m_tree->has_key(id)) - { - _writek_json(id); - this->Writer::_do_write(": "); - } - if(m_tree->is_seq(id)) - this->Writer::_do_write('['); - else if(m_tree->is_map(id)) - this->Writer::_do_write('{'); - } // container - - for(size_t ich = m_tree->first_child(id); ich != NONE; ich = m_tree->next_sibling(ich)) - { - if(ich != m_tree->first_child(id)) - this->Writer::_do_write(','); - _do_visit_json(ich); - } - - if(m_tree->is_seq(id)) - this->Writer::_do_write(']'); - else if(m_tree->is_map(id)) - this->Writer::_do_write('}'); -} - -template<class Writer> -void Emitter<Writer>::_write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t ilevel) -{ - if( ! sc.tag.empty()) - { - _write_tag(sc.tag); - this->Writer::_do_write(' '); - } - if(flags.has_anchor()) - { - RYML_ASSERT(flags.is_ref() != flags.has_anchor()); - RYML_ASSERT( ! sc.anchor.empty()); - this->Writer::_do_write('&'); - this->Writer::_do_write(sc.anchor); - this->Writer::_do_write(' '); - } - else if(flags.is_ref()) - { - if(sc.anchor != "<<") - this->Writer::_do_write('*'); - this->Writer::_do_write(sc.anchor); - return; - } - - // ensure the style flags only have one of KEY or VAL - _RYML_CB_ASSERT(m_tree->callbacks(), ((flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE)) == 0) || (((flags&_WIP_KEY_STYLE) == 0) != ((flags&_WIP_VAL_STYLE) == 0))); - - auto style_marks = flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE); - if(style_marks & (_WIP_KEY_LITERAL|_WIP_VAL_LITERAL)) - { - _write_scalar_literal(sc.scalar, ilevel, flags.has_key()); - } - else if(style_marks & (_WIP_KEY_FOLDED|_WIP_VAL_FOLDED)) - { - _write_scalar_folded(sc.scalar, ilevel, flags.has_key()); - } - else if(style_marks & (_WIP_KEY_SQUO|_WIP_VAL_SQUO)) - { - _write_scalar_squo(sc.scalar, ilevel); - } - else if(style_marks & (_WIP_KEY_DQUO|_WIP_VAL_DQUO)) - { - _write_scalar_dquo(sc.scalar, ilevel); - } - else if(style_marks & (_WIP_KEY_PLAIN|_WIP_VAL_PLAIN)) - { - _write_scalar_plain(sc.scalar, ilevel); - } - else if(!style_marks) - { - size_t first_non_nl = sc.scalar.first_not_of('\n'); - bool all_newlines = first_non_nl == npos; - bool has_leading_ws = (!all_newlines) && sc.scalar.sub(first_non_nl).begins_with_any(" \t"); - bool do_literal = ((!sc.scalar.empty() && all_newlines) || (has_leading_ws && !sc.scalar.trim(' ').empty())); - if(do_literal) - { - _write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws); - } - else - { - for(size_t i = 0; i < sc.scalar.len; ++i) - { - if(sc.scalar.str[i] == '\n') - { - _write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws); - goto wrote_special; - } - // todo: check for escaped characters requiring double quotes - } - _write_scalar(sc.scalar, flags.is_quoted()); - wrote_special: - ; - } - } - else - { - _RYML_CB_ERR(m_tree->callbacks(), "not implemented"); - } -} -template<class Writer> -void Emitter<Writer>::_write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags) -{ - if(C4_UNLIKELY( ! sc.tag.empty())) - _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have tags"); - if(C4_UNLIKELY(flags.has_anchor())) - _RYML_CB_ERR(m_tree->callbacks(), "JSON does not have anchors"); - _write_scalar_json(sc.scalar, flags.has_key(), flags.is_quoted()); -} - -#define _rymlindent_nextline() for(size_t lv = 0; lv < ilevel+1; ++lv) { this->Writer::_do_write(' '); this->Writer::_do_write(' '); } - -template<class Writer> -void Emitter<Writer>::_write_scalar_literal(csubstr s, size_t ilevel, bool explicit_key, bool explicit_indentation) -{ - if(explicit_key) - this->Writer::_do_write("? "); - csubstr trimmed = s.trimr("\n\r"); - size_t numnewlines_at_end = s.len - trimmed.len - s.sub(trimmed.len).count('\r'); - // - if(!explicit_indentation) - this->Writer::_do_write('|'); - else - this->Writer::_do_write("|2"); - // - if(numnewlines_at_end > 1 || (trimmed.len == 0 && s.len > 0)/*only newlines*/) - this->Writer::_do_write("+\n"); - else if(numnewlines_at_end == 1) - this->Writer::_do_write('\n'); - else - this->Writer::_do_write("-\n"); - // - if(trimmed.len) - { - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < trimmed.len; ++i) - { - if(trimmed[i] != '\n') - continue; - // write everything up to this point - csubstr since_pos = trimmed.range(pos, i+1); // include the newline - _rymlindent_nextline() - this->Writer::_do_write(since_pos); - pos = i+1; // already written - } - if(pos < trimmed.len) - { - _rymlindent_nextline() - this->Writer::_do_write(trimmed.sub(pos)); - } - if(numnewlines_at_end) - { - this->Writer::_do_write('\n'); - --numnewlines_at_end; - } - } - for(size_t i = 0; i < numnewlines_at_end; ++i) - { - _rymlindent_nextline() - if(i+1 < numnewlines_at_end || explicit_key) - this->Writer::_do_write('\n'); - } - if(explicit_key && !numnewlines_at_end) - this->Writer::_do_write('\n'); -} - -template<class Writer> -void Emitter<Writer>::_write_scalar_folded(csubstr s, size_t ilevel, bool explicit_key) -{ - if(explicit_key) - { - this->Writer::_do_write("? "); - } - RYML_ASSERT(s.find("\r") == csubstr::npos); - csubstr trimmed = s.trimr('\n'); - size_t numnewlines_at_end = s.len - trimmed.len; - if(numnewlines_at_end == 0) - { - this->Writer::_do_write(">-\n"); - } - else if(numnewlines_at_end == 1) - { - this->Writer::_do_write(">\n"); - } - else if(numnewlines_at_end > 1) - { - this->Writer::_do_write(">+\n"); - } - if(trimmed.len) - { - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < trimmed.len; ++i) - { - if(trimmed[i] != '\n') - continue; - // write everything up to this point - csubstr since_pos = trimmed.range(pos, i+1); // include the newline - pos = i+1; // because of the newline - _rymlindent_nextline() - this->Writer::_do_write(since_pos); - this->Writer::_do_write('\n'); // write the newline twice - } - if(pos < trimmed.len) - { - _rymlindent_nextline() - this->Writer::_do_write(trimmed.sub(pos)); - } - if(numnewlines_at_end) - { - this->Writer::_do_write('\n'); - --numnewlines_at_end; - } - } - for(size_t i = 0; i < numnewlines_at_end; ++i) - { - _rymlindent_nextline() - if(i+1 < numnewlines_at_end || explicit_key) - this->Writer::_do_write('\n'); - } - if(explicit_key && !numnewlines_at_end) - this->Writer::_do_write('\n'); -} - -template<class Writer> -void Emitter<Writer>::_write_scalar_squo(csubstr s, size_t ilevel) -{ - size_t pos = 0; // tracks the last character that was already written - this->Writer::_do_write('\''); - for(size_t i = 0; i < s.len; ++i) - { - if(s[i] == '\n') - { - csubstr sub = s.range(pos, i+1); - this->Writer::_do_write(sub); // write everything up to (including) this char - this->Writer::_do_write('\n'); // write the character again - if(i + 1 < s.len) - _rymlindent_nextline() // indent the next line - pos = i+1; - } - else if(s[i] == '\'') - { - csubstr sub = s.range(pos, i+1); - this->Writer::_do_write(sub); // write everything up to (including) this char - this->Writer::_do_write('\''); // write the character again - pos = i+1; - } - } - // write missing characters at the end of the string - if(pos < s.len) - this->Writer::_do_write(s.sub(pos)); - this->Writer::_do_write('\''); -} - -template<class Writer> -void Emitter<Writer>::_write_scalar_dquo(csubstr s, size_t ilevel) -{ - size_t pos = 0; // tracks the last character that was already written - this->Writer::_do_write('"'); - for(size_t i = 0; i < s.len; ++i) - { - const char curr = s.str[i]; - if(curr == '"' || curr == '\\') - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write('\\'); // write the escape - this->Writer::_do_write(curr); // write the char - pos = i+1; - } - else if(s[i] == '\n') - { - csubstr sub = s.range(pos, i+1); - this->Writer::_do_write(sub); // write everything up to (including) this newline - this->Writer::_do_write('\n'); // write the newline again - if(i + 1 < s.len) - _rymlindent_nextline() // indent the next line - pos = i+1; - if(i+1 < s.len) // escape leading whitespace after the newline - { - const char next = s.str[i+1]; - if(next == ' ' || next == '\t') - this->Writer::_do_write('\\'); - } - } - else if(curr == ' ' || curr == '\t') - { - // escape trailing whitespace before a newline - size_t next = s.first_not_of(" \t\r", i); - if(next != npos && s[next] == '\n') - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write('\\'); // escape the whitespace - pos = i; - } - } - else if(C4_UNLIKELY(curr == '\r')) - { - csubstr sub = s.range(pos, i); - this->Writer::_do_write(sub); // write everything up to (excluding) this char - this->Writer::_do_write("\\r"); // write the escaped char - pos = i+1; - } - } - // write missing characters at the end of the string - if(pos < s.len) - { - csubstr sub = s.sub(pos); - this->Writer::_do_write(sub); - } - this->Writer::_do_write('"'); -} - -template<class Writer> -void Emitter<Writer>::_write_scalar_plain(csubstr s, size_t ilevel) -{ - size_t pos = 0; // tracks the last character that was already written - for(size_t i = 0; i < s.len; ++i) - { - const char curr = s.str[i]; - if(curr == '\n') - { - csubstr sub = s.range(pos, i+1); - this->Writer::_do_write(sub); // write everything up to (including) this newline - this->Writer::_do_write('\n'); // write the newline again - if(i + 1 < s.len) - _rymlindent_nextline() // indent the next line - pos = i+1; - } - } - // write missing characters at the end of the string - if(pos < s.len) - { - csubstr sub = s.sub(pos); - this->Writer::_do_write(sub); - } -} - -#undef _rymlindent_nextline - -template<class Writer> -void Emitter<Writer>::_write_scalar(csubstr s, bool was_quoted) -{ - // this block of code needed to be moved to before the needs_quotes - // assignment to work around a g++ optimizer bug where (s.str != nullptr) - // was evaluated as true even if s.str was actually a nullptr (!!!) - if(s.len == size_t(0)) - { - if(was_quoted || s.str != nullptr) - this->Writer::_do_write("''"); - return; - } - - const bool needs_quotes = ( - was_quoted - || - ( - ( ! s.is_number()) - && - ( - // has leading whitespace - // looks like reference or anchor - // would be treated as a directive - // see https://www.yaml.info/learn/quote.html#noplain - s.begins_with_any(" \n\t\r*&%@`") - || - s.begins_with("<<") - || - // has trailing whitespace - s.ends_with_any(" \n\t\r") - || - // has special chars - (s.first_of("#:-?,\n{}[]'\"") != npos) - ) - ) - ); - - if( ! needs_quotes) - { - this->Writer::_do_write(s); - } - else - { - const bool has_dquotes = s.first_of( '"') != npos; - const bool has_squotes = s.first_of('\'') != npos; - if(!has_squotes && has_dquotes) - { - this->Writer::_do_write('\''); - this->Writer::_do_write(s); - this->Writer::_do_write('\''); - } - else if(has_squotes && !has_dquotes) - { - RYML_ASSERT(s.count('\n') == 0); - this->Writer::_do_write('"'); - this->Writer::_do_write(s); - this->Writer::_do_write('"'); - } - else - { - _write_scalar_squo(s, /*FIXME FIXME FIXME*/0); - } - } -} -template<class Writer> -void Emitter<Writer>::_write_scalar_json(csubstr s, bool as_key, bool use_quotes) -{ - if((!use_quotes) - // json keys require quotes - && (!as_key) - && ( - // do not quote special cases - (s == "true" || s == "false" || s == "null") - || ( - // do not quote numbers - (s.is_number() - && ( - // quote integral numbers if they have a leading 0 - // https://github.com/biojppm/rapidyaml/issues/291 - (!(s.len > 1 && s.begins_with('0'))) - // do not quote reals with leading 0 - // https://github.com/biojppm/rapidyaml/issues/313 - || (s.find('.') != csubstr::npos) )) - ) - ) - ) - { - this->Writer::_do_write(s); - } - else - { - size_t pos = 0; - this->Writer::_do_write('"'); - for(size_t i = 0; i < s.len; ++i) - { - switch(s.str[i]) - { - case '"': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\\""); - pos = i + 1; - break; - case '\n': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\n"); - pos = i + 1; - break; - case '\t': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\t"); - pos = i + 1; - break; - case '\\': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\\\"); - pos = i + 1; - break; - case '\r': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\r"); - pos = i + 1; - break; - case '\b': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\b"); - pos = i + 1; - break; - case '\f': - this->Writer ::_do_write(s.range(pos, i)); - this->Writer ::_do_write("\\f"); - pos = i + 1; - break; - } - } - if(pos < s.len) - { - csubstr sub = s.sub(pos); - this->Writer::_do_write(sub); - } - this->Writer::_do_write('"'); - } -} - -} // namespace yml -} // namespace c4 - -#endif /* _C4_YML_EMIT_DEF_HPP_ */ |