From 2e19c005f6071d9da68bbd3a12bdcfb5039aa232 Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Wed, 29 Oct 2025 18:11:59 +0000 Subject: [PATCH] Prepare emitter for comments --- changelog/current.md | 3 +- samples/quickstart.cpp | 4 +- src/c4/yml/emit.def.hpp | 523 ++++++++---------- src/c4/yml/emit.hpp | 118 ++-- src/c4/yml/event_handler_tree.hpp | 13 +- src/c4/yml/node_type.cpp | 3 +- src/c4/yml/tree.cpp | 2 +- src_extra/c4/yml/extra/event_handler_ints.cpp | 34 ++ src_extra/c4/yml/extra/event_handler_ints.hpp | 90 +-- .../c4/yml/extra/event_handler_testsuite.cpp | 2 +- test/test_emit.cpp | 72 ++- test/test_engine_4_anchor.cpp | 135 ++++- test/test_engine_5_tag.cpp | 4 +- 13 files changed, 566 insertions(+), 437 deletions(-) diff --git a/changelog/current.md b/changelog/current.md index dfe7f601..f8025b33 100644 --- a/changelog/current.md +++ b/changelog/current.md @@ -38,8 +38,9 @@ - Added `ParserOptions::detect_flow_ml()` to control this behavior - Added `EmitOptions::indent_flow_ml()` to control indentation of FLOW_ML containers - The emit implementation logic was refactored, and is now significantly cleaner + - Emitted YAML will now have anchors emitted before tags, as is customary ([see example](https://play.yaml.io/main/parser?input=LSAhdGFnICZhbmNob3IgfAogIG5vdGUgaG93IHRoZSBhbmNob3IgY29tZXMKICBmaXJzdCBpbiB0aGUgZXZlbnRz)). - Added `ParserOptions` defaulted argument to temp-parser overloads of `parse_{yaml,json}_in_{place,arena}()` -- [PR#503](https://github.com/biojppm/rapidyaml/pull/503) (fixes [#399](https://github.com/biojppm/rapidyaml/issues/399)): change error callbacks. + [PR#503](https://github.com/biojppm/rapidyaml/pull/503) (fixes [#399](https://github.com/biojppm/rapidyaml/issues/399)): change error callbacks. - Errors in ryml now have one of these types: - parse error: when parsing YAML/JSON. See: `pfn_error_parse`, `ErrorDataParse`, `ExceptionParse`, `err_parse_format()`, `sample_error_parse`. - visit error: when visiting a tree (reading or writing). See: `pfn_error_visit`, `ErrorDataVisit`, `ExceptionVisit`, `err_visit_format()`, `sample_error_visit`. diff --git a/samples/quickstart.cpp b/samples/quickstart.cpp index d71fa9f2..06a25ae0 100644 --- a/samples/quickstart.cpp +++ b/samples/quickstart.cpp @@ -4305,7 +4305,7 @@ void sample_emit_nested_node() * formatting of emitted YAML code. */ void sample_style() { - // we will be using these helpers throughout this function + // we will be using this helper throughout this function auto tostr = [](ryml::ConstNodeRef n) { return ryml::emitrs_yaml(n); }; // let's parse this: ryml::csubstr yaml = R"(block map: @@ -4473,7 +4473,7 @@ block seq: )"); // you can set the style based on type conditions: // set a single key to single-quoted - tree["block map"].set_style_conditionally(ryml::KEY, + tree["block map"].set_style_conditionally(/*type_mask*/ryml::KEY, /*remflags*/ryml::KEY_STYLE, /*addflags*/ryml::KEY_SQUO, /*recurse*/false); diff --git a/src/c4/yml/emit.def.hpp b/src/c4/yml/emit.def.hpp index ef6c5f35..16b4f105 100644 --- a/src/c4/yml/emit.def.hpp +++ b/src/c4/yml/emit.def.hpp @@ -10,6 +10,8 @@ #include "c4/yml/detail/dbgprint.hpp" #endif +C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast") + namespace c4 { namespace yml { @@ -30,13 +32,9 @@ substr Emitter::emit_as(EmitType_e type, Tree const& tree, id_type id, b m_ilevel = 0; m_pws = _PWS_NONE; if(type == EMIT_YAML) - { _emit_yaml(id); - } else if(type == EMIT_JSON) - { _emit_json(id); - } else _RYML_ERR_BASIC_(m_tree->callbacks(), "unknown emit type"); // LCOV_EXCL_LINE m_tree = nullptr; @@ -108,12 +106,12 @@ void Emitter::_emit_yaml(id_type id) if(emit_key) { --m_ilevel; - _blck_map_close_entry(id); + _blck_close_entry(id); } else if(emit_dash) { --m_ilevel; - _blck_seq_close_entry(id); + _blck_close_entry(id); } else { @@ -121,12 +119,16 @@ void Emitter::_emit_yaml(id_type id) } if(ty.is_flow_ml()) + { _newl(); + } else if(m_tree->is_root(id) || emit_dash || emit_key || !ty.is_val() - || ty.is_val_literal() || ty.is_val_folded()) + || !ty.is_val_plain()) + { _write_pws_and_pend(_PWS_NONE); + } } @@ -147,12 +149,12 @@ void Emitter::_visit_stream(id_type id) const id_type parent = m_tree->parent(next_node); for( ; tagds.b != end; ++tagds.b) { - _write_pws_and_pend(_PWS_NONE); if(next_node != m_tree->first_child(parent)) { + _write_pws_and_pend(_PWS_NEWL); _write("..."); - _newl(); } + _write_pws_and_pend(_PWS_NONE); _write("%TAG "); _write(tagds.b->handle); _write(' '); @@ -171,10 +173,20 @@ void Emitter::_visit_stream(id_type id) _top_open_entry(child); _visit_doc(child); _top_close_entry(child); - if(m_pws == _PWS_NONE) - _pend_newl(); + if(m_tree->is_val(child)) + { + if(m_tree->type(child) & VALNIL) + _pend_newl(); + } + else if(m_tree->is_container(child)) + { + if(m_tree->is_flow(child)) + _pend_newl(); + } if(m_tree->next_sibling(child) != NONE) + { write_tag_directives(m_tree->next_sibling(child)); + } } --m_depth; } @@ -220,8 +232,8 @@ void Emitter::_visit_doc_val(id_type id) // appear at 0-indentation NodeType ty = m_tree->type(id); const csubstr val = m_tree->val(id); - const type_bits has_style_marks = ty & VAL_STYLE; - const bool is_ambiguous = (ty.is_val_plain() || !has_style_marks) + const type_bits val_style = ty & VAL_STYLE; + const bool is_ambiguous = ((ty & VAL_PLAIN) || !val_style) && (val.begins_with("...") || val.begins_with("---")); if(is_ambiguous) { @@ -238,13 +250,14 @@ void Emitter::_visit_doc_val(id_type id) } else { - _blck_write_scalar_val(id); + if(!val_style) + ty = scalar_style_choose(val); + _blck_write_scalar(val, val_style); } if(is_ambiguous) { --m_ilevel; } - _pend_newl(); } @@ -256,7 +269,6 @@ void Emitter::_visit_doc(id_type id) const NodeType ty = m_tree->type(id); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, ty.is_doc(), m_tree, id); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, !ty.has_key(), m_tree, id); - if(ty.is_container()) // this is more frequent { _visit_blck_container(id); @@ -280,17 +292,17 @@ void Emitter::_top_open_entry(id_type node) _write("---"); _pend_space(); } - if(ty.has_val_tag()) - { - _write_pws_and_pend(_PWS_SPACE); - _write_tag(m_tree->val_tag(node)); - } if(ty.has_val_anchor()) { _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->val_anchor(node)); } + if(ty.has_val_tag()) + { + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->val_tag(node)); + } if(m_pws == _PWS_SPACE) { if(ty.has_val()) @@ -313,27 +325,10 @@ void Emitter::_top_open_entry(id_type node) template void Emitter::_top_close_entry(id_type node) { - (void)node; -} - - -//----------------------------------------------------------------------------- - -template -void Emitter::_flow_sl_write_comma(id_type node, id_type first_sibling) -{ - _RYML_ASSERT_VISIT_(m_tree->callbacks(), first_sibling == m_tree->first_sibling(node), m_tree, node); - if(node != first_sibling) - _write(','); -} - -template -void Emitter::_flow_ml_write_comma(id_type node, id_type last_sibling) -{ - _RYML_ASSERT_VISIT_(m_tree->callbacks(), last_sibling == m_tree->last_sibling(node), m_tree, node); - if(node != last_sibling) - _write(','); - _pend_newl(); + if(m_tree->is_val(node) && !(m_tree->type(node) & VALNIL)) + { + _pend_newl(); + } } @@ -344,27 +339,17 @@ void Emitter::_flow_seq_open_entry(id_type node) { NodeType ty = m_tree->type(node); _write_pws_and_pend(_PWS_NONE); - if(ty.has_val_tag()) - { - _write_tag(m_tree->val_tag(node)); - _pend_space(); - } - if(ty.has_val_anchor()) + if(ty & VALANCH) { _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->val_anchor(node)); } -} - - -//----------------------------------------------------------------------------- - -template -void Emitter::_flow_seq_close_entry(id_type node) -{ - (void)node; - _write_pws_and_pend(_PWS_NONE); + if(ty & VALTAG) + { + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->val_tag(node)); + } } @@ -376,18 +361,18 @@ void Emitter::_flow_map_open_entry(id_type node) NodeType ty = m_tree->type(node); _write_pws_and_pend(_PWS_NONE); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key(), m_tree, node); - if(ty.has_key_tag()) - { - _write_tag(m_tree->key_tag(node)); - _pend_space(); - } - if(ty.has_key_anchor()) + if(ty & KEYANCH) { _write_pws_and_pend(_PWS_SPACE); _write("&"); _write(m_tree->key_anchor(node)); } - if(ty.is_key_ref()) + if(ty & KEYTAG) + { + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->key_tag(node)); + } + if(ty & KEYREF) { _write_pws_and_pend(_PWS_SPACE); _write_ref(m_tree->key(node)); @@ -395,31 +380,48 @@ void Emitter::_flow_map_open_entry(id_type node) else { _write_pws_and_pend(_PWS_NONE); - _blck_write_scalar_key(node); + csubstr key = m_tree->key(node); + if(!(ty & (NodeType_e)_styles_flow_key)) + ty |= scalar_style_choose(key) & (NodeType_e)_styles_flow_key; + _flow_write_scalar(key, ty & (NodeType_e)_styles_flow_key); } _write_pws_and_pend(_PWS_SPACE); _write(':'); - if(ty.has_val_tag()) - { - _write_pws_and_pend(_PWS_SPACE); - _write_tag(m_tree->val_tag(node)); - } - if(ty.has_val_anchor()) + if(ty & VALANCH) { _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->val_anchor(node)); } + if(ty & VALTAG) + { + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->val_tag(node)); + } } //----------------------------------------------------------------------------- template -void Emitter::_flow_map_close_entry(id_type node) +void Emitter::_flow_close_entry_sl(id_type node, id_type last_sibling) { - (void)node; - _write_pws_and_pend(_PWS_NONE); + if(node != last_sibling) + { + _write_pws_and_pend(_PWS_NONE); + _write(','); + } +} + +template +void Emitter::_flow_close_entry_ml(id_type node, id_type last_sibling) +{ + if(node != last_sibling) + { + _write_pws_and_pend(_PWS_NONE); + _write(','); + } + _pend_newl(); } @@ -433,24 +435,24 @@ void Emitter::_blck_seq_open_entry(id_type node) _write_pws_and_pend(_PWS_SPACE); // pend the space after the following dash _write('-'); bool has_tag_or_anchor = false; - if(ty.has_val_tag()) - { - has_tag_or_anchor = true; - _write_pws_and_pend(_PWS_SPACE); - _write_tag(m_tree->val_tag(node)); - } - if(ty.has_val_anchor()) + if(ty & VALANCH) { has_tag_or_anchor = true; _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->val_anchor(node)); } + if(ty & VALTAG) + { + has_tag_or_anchor = true; + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->val_tag(node)); + } if(has_tag_or_anchor && ty.is_container()) { if(!(ty & CONTAINER_STYLE)) ty |= BLOCK; - if(ty.is_block() && m_tree->has_children(node)) + if((ty & BLOCK) && m_tree->has_children(node)) _pend_newl(); } } @@ -459,10 +461,12 @@ void Emitter::_blck_seq_open_entry(id_type node) //----------------------------------------------------------------------------- template -void Emitter::_blck_seq_close_entry(id_type node) +void Emitter::_blck_write_qmrk(id_type node, csubstr key, type_bits ty, bool has_qmrk_comments) { (void)node; - _pend_newl(); + (void)key; + (void)ty; + (void)has_qmrk_comments; } @@ -473,43 +477,54 @@ void Emitter::_blck_map_open_entry(id_type node) { _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_key(node), m_tree, node); NodeType ty = m_tree->type(node); + csubstr key = m_tree->key(node); + if(!(ty & (KEY_STYLE|KEYREF))) + ty |= (scalar_style_choose(key) & KEY_STYLE); _write_pws_and_pend(_PWS_NONE); - if(ty.has_key_tag()) - { - _write_pws_and_pend(_PWS_SPACE); - _write_tag(m_tree->key_tag(node)); - } - if(ty.has_key_anchor()) + if(ty & KEYANCH) { _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->key_anchor(node)); } - if(ty.is_key_ref()) + if(ty & KEYTAG) { _write_pws_and_pend(_PWS_SPACE); - _write_ref(m_tree->key(node)); + _write_tag(m_tree->key_tag(node)); + } + if(ty & KEYREF) + { + _write_pws_and_pend(_PWS_SPACE); + _write_ref(key); } else { _write_pws_and_pend(_PWS_NONE); - _blck_write_scalar_key(node); - if(ty & (KEY_LITERAL|KEY_FOLDED)) - _indent(m_ilevel); + type_bits use_qmrk = ty & (NodeType_e)_styles_block_key; + if(!use_qmrk) + { + _blck_write_scalar(key, ty & KEY_STYLE); + } + else + { + _write("? "); + _blck_write_scalar(key, ty & KEY_STYLE); + _pend_newl(); + } } _write_pws_and_pend(_PWS_SPACE); // pend the space after the colon _write(':'); - if(ty.has_val_tag()) - { - _write_pws_and_pend(_PWS_SPACE); - _write_tag(m_tree->val_tag(node)); - } - if(ty.has_val_anchor()) + if(ty & VALANCH) { _write_pws_and_pend(_PWS_SPACE); _write('&'); _write(m_tree->val_anchor(node)); } + if(ty & VALTAG) + { + _write_pws_and_pend(_PWS_SPACE); + _write_tag(m_tree->val_tag(node)); + } if(ty.is_container() && m_tree->has_children(node)) { if(!(ty & CONTAINER_STYLE)) @@ -523,7 +538,7 @@ void Emitter::_blck_map_open_entry(id_type node) //----------------------------------------------------------------------------- template -void Emitter::_blck_map_close_entry(id_type node) +void Emitter::_blck_close_entry(id_type node) { (void)node; _pend_newl(); @@ -540,16 +555,23 @@ void Emitter::_visit_blck_seq(id_type node) for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child)) { empty = false; - const NodeType ty = m_tree->type(child); + NodeType ty = m_tree->type(child); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node); _blck_seq_open_entry(child); if(ty.is_val()) { _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); if(!ty.is_val_ref()) - _blck_write_scalar_val(child); + { + if(!(ty & VAL_STYLE)) + ty |= (scalar_style_choose(val) & VAL_STYLE); + _blck_write_scalar(val, ty & VAL_STYLE); + } else - _write_ref(m_tree->val(child)); + { + _write_ref(val); + } } else if(ty.is_container()) { @@ -559,7 +581,7 @@ void Emitter::_visit_blck_seq(id_type node) --m_depth; --m_ilevel; } - _blck_seq_close_entry(child); + _blck_close_entry(child); } if(empty) { @@ -579,16 +601,23 @@ void Emitter::_visit_blck_map(id_type node) for(id_type child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child)) { empty = false; - const NodeType ty = m_tree->type(child); + NodeType ty = m_tree->type(child); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_keyval() || ty.is_container() || ty == NOTYPE, m_tree, node); _blck_map_open_entry(child); // also writes the key if(ty.is_keyval()) { _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); if(!ty.is_val_ref()) - _blck_write_scalar_val(child); + { + if(!(ty & VAL_STYLE)) + ty |= (scalar_style_choose(val) & VAL_STYLE); + _blck_write_scalar(val, ty & VAL_STYLE); + } else - _write_ref(m_tree->val(child)); + { + _write_ref(val); + } } else if(ty.is_container()) { @@ -598,7 +627,7 @@ void Emitter::_visit_blck_map(id_type node) --m_depth; --m_ilevel; } - _blck_map_close_entry(child); + _blck_close_entry(child); } if(empty) { @@ -615,19 +644,25 @@ void Emitter::_visit_flow_sl_seq(id_type node) { _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node); _write('['); - for(id_type first = m_tree->first_child(node), child = first; child != NONE; child = m_tree->next_sibling(child)) + for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child)) { - _flow_sl_write_comma(child, first); - const NodeType ty = m_tree->type(child); + NodeType ty = m_tree->type(child); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node); _flow_seq_open_entry(child); if(ty.is_val()) { _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); if(!ty.is_val_ref()) - _flow_write_scalar_val(child); + { + if(!(ty & (NodeType_e)_styles_flow_val)) + ty |= (scalar_style_choose(val) & (NodeType_e)_styles_flow_val); + _flow_write_scalar(val, ty & (NodeType_e)_styles_flow_val); + } else - _write_ref(m_tree->val(child)); + { + _write_ref(val); + } } else if(ty.is_container()) { @@ -635,12 +670,55 @@ void Emitter::_visit_flow_sl_seq(id_type node) _visit_flow_container(child); --m_depth; } - _flow_seq_close_entry(child); + _flow_close_entry_sl(child, last); } _write(']'); } +//----------------------------------------------------------------------------- + +template +void Emitter::_visit_flow_ml_seq(id_type node) +{ + _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node); + _write('['); + _pend_newl(); + if(m_opts.indent_flow_ml()) ++m_ilevel; + for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child)) + { + NodeType ty = m_tree->type(child); + _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node); + _flow_seq_open_entry(child); + if(ty.is_val()) + { + _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); + if(!ty.is_val_ref()) + { + if(!(ty & (NodeType_e)_styles_flow_val)) + ty |= (scalar_style_choose(val) & (NodeType_e)_styles_flow_val); + _flow_write_scalar(val, ty & (NodeType_e)_styles_flow_val); + } + else + { + _write_ref(val); + } + } + else if(ty.is_container()) + { + ++m_depth; + _visit_flow_container(child); + --m_depth; + } + _flow_close_entry_ml(child, last); + } + if(m_opts.indent_flow_ml()) --m_ilevel; + _write_pws_and_pend(_PWS_NONE); + _write(']'); +} + + //----------------------------------------------------------------------------- template @@ -648,19 +726,25 @@ void Emitter::_visit_flow_sl_map(id_type node) { _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node); _write('{'); - for(id_type first = m_tree->first_child(node), child = first; child != NONE; child = m_tree->next_sibling(child)) + for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child)) { - _flow_sl_write_comma(child, first); - const NodeType ty = m_tree->type(child); + NodeType ty = m_tree->type(child); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty == NOTYPE), m_tree, node); _flow_map_open_entry(child); if(ty.has_val()) { _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); if(!ty.is_val_ref()) - _flow_write_scalar_val(child); + { + if(!(ty & (NodeType_e)_styles_flow_val)) + ty |= (scalar_style_choose(val) & (NodeType_e)_styles_flow_val); + _flow_write_scalar(val, ty & (NodeType_e)_styles_flow_val); + } else - _write_ref(m_tree->val(child)); + { + _write_ref(val); + } } else if(ty.is_container()) { @@ -668,8 +752,9 @@ void Emitter::_visit_flow_sl_map(id_type node) _visit_flow_container(child); --m_depth; } - _flow_map_close_entry(child); + _flow_close_entry_sl(child, last); } + _write_pws_and_pend(_PWS_NONE); _write('}'); } @@ -685,16 +770,23 @@ void Emitter::_visit_flow_ml_map(id_type node) if(m_opts.indent_flow_ml()) ++m_ilevel; for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child)) { - const NodeType ty = m_tree->type(child); + NodeType ty = m_tree->type(child); _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.has_key() && (ty.has_val() || ty.is_container() || ty == NOTYPE), m_tree, node); _flow_map_open_entry(child); if(ty.has_val()) { _write_pws_and_pend(_PWS_NONE); + csubstr val = m_tree->val(child); if(!ty.is_val_ref()) - _flow_write_scalar_val(child); + { + if(!(ty & (NodeType_e)_styles_flow_val)) + ty |= (scalar_style_choose(val) & (NodeType_e)_styles_flow_val); + _flow_write_scalar(val, ty & (NodeType_e)_styles_flow_val); + } else - _write_ref(m_tree->val(child)); + { + _write_ref(val); + } } else if(ty.is_container()) { @@ -702,8 +794,7 @@ void Emitter::_visit_flow_ml_map(id_type node) _visit_flow_container(child); --m_depth; } - _flow_map_close_entry(child); - _flow_ml_write_comma(child, last); + _flow_close_entry_ml(child, last); } if(m_opts.indent_flow_ml()) --m_ilevel; _write_pws_and_pend(_PWS_NONE); @@ -711,43 +802,6 @@ void Emitter::_visit_flow_ml_map(id_type node) } -//----------------------------------------------------------------------------- - -template -void Emitter::_visit_flow_ml_seq(id_type node) -{ - _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node); - _write('['); - _pend_newl(); - if(m_opts.indent_flow_ml()) ++m_ilevel; - for(id_type child = m_tree->first_child(node), last = m_tree->last_child(node); child != NONE; child = m_tree->next_sibling(child)) - { - const NodeType ty = m_tree->type(child); - _RYML_ASSERT_VISIT_(m_tree->callbacks(), ty.is_val() || ty.is_container() || ty == NOTYPE, m_tree, node); - _flow_seq_open_entry(child); - if(ty.is_val()) - { - _write_pws_and_pend(_PWS_NONE); - if(!ty.is_val_ref()) - _flow_write_scalar_val(child); - else - _write_ref(m_tree->val(child)); - } - else if(ty.is_container()) - { - ++m_depth; - _visit_flow_container(child); - --m_depth; - } - _flow_seq_close_entry(child); - _flow_ml_write_comma(child, last); - } - if(m_opts.indent_flow_ml()) --m_ilevel; - _write_pws_and_pend(_PWS_NONE); - _write(']'); -} - - //----------------------------------------------------------------------------- template @@ -820,140 +874,45 @@ void Emitter::_visit_flow_ml(id_type node) //----------------------------------------------------------------------------- template -void Emitter::_flow_write_scalar_key(id_type id) +void Emitter::_flow_write_scalar(csubstr str, type_bits ty) { - enum : type_bits { - _block_styles = (KEY_LITERAL|KEY_FOLDED), - _flow_styles = KEY_STYLE & ~(KEY_LITERAL|KEY_FOLDED), - }; - csubstr str = m_tree->key(id); - NodeType ty = m_tree->type(id) & static_cast(_flow_styles); - if(!(ty & KEY_STYLE)) - ty |= scalar_style_choose(str); - _RYML_ASSERT_VISIT_(m_tree->callbacks(), !(ty & (KEY_LITERAL|KEY_FOLDED)), m_tree, id); - if(ty & KEY_PLAIN) + _RYML_ASSERT_BASIC_(m_tree->callbacks(), !(ty & _styles_block)); + if((ty & _styles_plain) || !(ty & SCALAR_STYLE)) { - if(C4_LIKELY(!(str.begins_with(": ") || str.begins_with(":\t")))) - _write_scalar_plain(str, m_ilevel); - else - _write_scalar_squo(str, m_ilevel); + _write_scalar_plain(str, m_ilevel); } - else if(ty & KEY_SQUO) + else if(ty & _styles_squo) { _write_scalar_squo(str, m_ilevel); } - else if(ty & KEY_DQUO) + else // if(ty & _styles_dquo) { _write_scalar_dquo(str, m_ilevel); } - else - { - _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, id, "not implemented"); // LCOV_EXCL_LINE - } } template -void Emitter::_flow_write_scalar_val(id_type id) +void Emitter::_blck_write_scalar(csubstr str, type_bits ty) { - enum : type_bits { - _block_styles = VAL_LITERAL|VAL_FOLDED, - _flow_styles = (VAL_STYLE) & (~(VAL_LITERAL|VAL_FOLDED)), - }; - csubstr str = m_tree->val(id); - NodeType ty = m_tree->type(id) & static_cast(_flow_styles); - if(!(ty & VAL_STYLE)) - ty |= scalar_style_choose(str); - _RYML_ASSERT_VISIT_(m_tree->callbacks(), !(ty & (VAL_LITERAL|VAL_FOLDED)), m_tree, id); - if(ty & VAL_PLAIN) + if((ty & _styles_plain) || !(ty & SCALAR_STYLE)) { - if(C4_LIKELY(!(str.begins_with(": ") || str.begins_with(":\t")))) - _write_scalar_plain(str, m_ilevel); - else - _write_scalar_squo(str, m_ilevel); + _write_scalar_plain(str, m_ilevel); } - else if(ty & VAL_SQUO) + else if(ty & _styles_squo) { _write_scalar_squo(str, m_ilevel); } - else if(ty & VAL_DQUO) + else if(ty & _styles_dquo) { _write_scalar_dquo(str, m_ilevel); } - else + else if(ty & _styles_literal) { - _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, id, "not implemented"); // LCOV_EXCL_LINE + _write_scalar_literal(str, m_ilevel); } -} - -template -void Emitter::_blck_write_scalar_key(id_type id) -{ - csubstr key = m_tree->key(id); - NodeType ty = m_tree->type(id); - if(!(ty & KEY_STYLE)) - ty |= scalar_style_choose(key); - if(ty & KEY_PLAIN) + else // if(ty & _styles_folded) { - if(C4_LIKELY(!(key.begins_with(": ") || key.begins_with(":\t")))) - _write_scalar_plain(key, m_ilevel); - else - _write_scalar_squo(key, m_ilevel); - } - else if(ty & KEY_SQUO) - { - _write_scalar_squo(key, m_ilevel); - } - else if(ty & KEY_DQUO) - { - _write_scalar_dquo(key, m_ilevel); - } - else if(ty & KEY_LITERAL) - { - _write_scalar_literal(key, m_ilevel, /*explicit*/true); - } - else if(ty & KEY_FOLDED) - { - _write_scalar_folded(key, m_ilevel, /*explicit*/true); - } - else - { - _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, NONE, "not implemented"); // LCOV_EXCL_LINE - } -} - -template -void Emitter::_blck_write_scalar_val(id_type id) -{ - csubstr str = m_tree->val(id); - NodeType ty = m_tree->type(id); - if(!(ty & VAL_STYLE)) - ty |= scalar_style_choose(str); - if(ty & VAL_PLAIN) - { - if(C4_LIKELY(!(str.begins_with(": ") || str.begins_with(":\t")))) - _write_scalar_plain(str, m_ilevel); - else - _write_scalar_squo(str, m_ilevel); - } - else if(ty & VAL_SQUO) - { - _write_scalar_squo(str, m_ilevel); - } - else if(ty & VAL_DQUO) - { - _write_scalar_dquo(str, m_ilevel); - } - else if(ty & VAL_LITERAL) - { - _write_scalar_literal(str, m_ilevel, /*explicit*/false); - } - else if(ty & VAL_FOLDED) - { - _write_scalar_folded(str, m_ilevel, /*explicit*/false); - } - else - { - _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, NONE, "not implemented"); // LCOV_EXCL_LINE + _write_scalar_folded(str, m_ilevel); } } @@ -1024,11 +983,9 @@ again: } template -void Emitter::_write_scalar_literal(csubstr s, id_type ilevel, bool explicit_key) +void Emitter::_write_scalar_literal(csubstr s, id_type ilevel) { _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find("\r") == csubstr::npos); - if(explicit_key) - _write("? "); csubstr trimmed = s.trimr('\n'); const size_t numnewlines_at_end = s.len - trimmed.len; const bool is_newline_only = (trimmed.len == 0 && (s.len > 0)); @@ -1065,15 +1022,11 @@ void Emitter::_write_scalar_literal(csubstr s, id_type ilevel, bool expl } for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i) _newl(); - if(explicit_key) - _newl(); } template -void Emitter::_write_scalar_folded(csubstr s, id_type ilevel, bool explicit_key) +void Emitter::_write_scalar_folded(csubstr s, id_type ilevel) { - if(explicit_key) - _write("? "); _RYML_ASSERT_BASIC_(m_tree->callbacks(), s.find("\r") == csubstr::npos); csubstr trimmed = s.trimr('\n'); const size_t numnewlines_at_end = s.len - trimmed.len; @@ -1143,8 +1096,6 @@ void Emitter::_write_scalar_folded(csubstr s, id_type ilevel, bool expli } for(size_t i = !is_newline_only; i < numnewlines_at_end; ++i) _newl(); - if(explicit_key) - _newl(); } template @@ -1528,4 +1479,6 @@ void Emitter::_write_scalar_json_dquo(csubstr s) } // namespace yml } // namespace c4 +C4_SUPPRESS_WARNING_GCC_CLANG_POP + #endif /* _C4_YML_EMIT_DEF_HPP_ */ diff --git a/src/c4/yml/emit.hpp b/src/c4/yml/emit.hpp index dfca5d97..4f738c23 100644 --- a/src/c4/yml/emit.hpp +++ b/src/c4/yml/emit.hpp @@ -136,9 +136,9 @@ public: * @param opts @ref EmitOptions * @param args arguments to be forwarded to the constructor of the writer. */ - template - Emitter(EmitOptions const& opts, Args &&...args) - : Writer(std::forward(args)...) + template + Emitter(EmitOptions const& opts, WriterArgs &&...args) + : Writer(std::forward(args)...) , m_tree() , m_opts(opts) , m_col() @@ -150,9 +150,9 @@ public: /** Construct the emitter and its internal Writer state, using default emit options. * @param args arguments to be forwarded to the constructor of the writer. */ - template - Emitter(Args &&...args) - : Writer(std::forward(args)...) + template + Emitter(WriterArgs &&...args) + : Writer(std::forward(args)...) , m_tree() , m_opts() , m_col() @@ -208,10 +208,10 @@ public: /** get the max depth for emitted trees (to prevent a stack overflow) */ id_type max_depth() const noexcept { return m_opts.max_depth(); } - /** @cond dev */ - private: + /** @cond dev */ + void _emit_yaml(id_type id); void _visit_stream(id_type id); @@ -235,30 +235,26 @@ private: void _top_open_entry(id_type id); void _top_close_entry(id_type id); void _blck_seq_open_entry(id_type id); - void _blck_seq_close_entry(id_type id); void _blck_map_open_entry(id_type id); - void _blck_map_close_entry(id_type id); - void _blck_write_scalar_key(id_type id); - void _blck_write_scalar_val(id_type id); + void _blck_close_entry(id_type id); + void _blck_write_qmrk(id_type id, csubstr key, type_bits type, bool has_qmrk_comments); + void _blck_write_scalar(csubstr str, type_bits type); void _flow_seq_open_entry(id_type id); - void _flow_seq_close_entry(id_type id); void _flow_map_open_entry(id_type id); - void _flow_map_close_entry(id_type id); - void _flow_write_scalar_key(id_type id); - void _flow_write_scalar_val(id_type id); - - void _flow_sl_write_comma(id_type id, id_type first_sibling); - void _flow_ml_write_comma(id_type id, id_type first_sibling); + void _flow_close_entry_sl(id_type id, id_type last_sibling); + void _flow_close_entry_ml(id_type id, id_type last_sibling); + void _flow_write_scalar(csubstr str, type_bits type); private: void _emit_json(id_type id); - void _write_scalar_literal(csubstr s, id_type level, bool as_key); - void _write_scalar_folded(csubstr s, id_type level, bool as_key); + void _write_scalar_literal(csubstr s, id_type level); + void _write_scalar_folded(csubstr s, id_type level); void _write_scalar_squo(csubstr s, id_type level); void _write_scalar_dquo(csubstr s, id_type level); void _write_scalar_plain(csubstr s, id_type level); + size_t _write_escaped_newlines(csubstr s, size_t i); size_t _write_indented_block(csubstr s, size_t i, id_type level); @@ -288,42 +284,48 @@ private: } } - void _indent(id_type level) +private: + + C4_ALWAYS_INLINE void _indent(id_type level) { - _write(' ', 2u * (size_t)level); + size_t num = (size_t)(2u * level); + this->Writer::_do_write(' ', num); + m_col += num; + } + + template + C4_ALWAYS_INLINE void _write(const char (&a)[N]) + { + this->Writer::_do_write(std::forward(a)); + m_col += N-1; + } + C4_ALWAYS_INLINE void _write(csubstr s) + { + this->Writer::_do_write(s); + m_col += s.len; + } + C4_ALWAYS_INLINE void _write(char c) + { + this->Writer::_do_write(c); + ++m_col; + } + C4_ALWAYS_INLINE void _write(char c, size_t num) + { + this->Writer::_do_write(c, num); + m_col += num; } /// write a newline and reset the column C4_ALWAYS_INLINE void _newl() { - m_col = 0; this->Writer::_do_write('\n'); - } - template - C4_ALWAYS_INLINE void _write(const char (&a)[N]) - { - m_col += N-1; - this->Writer::_do_write(std::forward(a)); - } - C4_ALWAYS_INLINE void _write(csubstr s) - { - m_col += s.len; - this->Writer::_do_write(s); - } - C4_ALWAYS_INLINE void _write(char c) - { - ++m_col; - this->Writer::_do_write(c); - } - C4_ALWAYS_INLINE void _write(char c, size_t num) - { - m_col += num; - this->Writer::_do_write(c, num); + m_col = 0; } private: // pending whitespace - typedef enum : uint32_t { _PWS_NONE, _PWS_SPACE, _PWS_NEWL } Pws_e; ///< pending whitespace + /// pending whitespace + typedef enum : uint32_t { _PWS_NONE, _PWS_SPACE, _PWS_NEWL } Pws_e; /// set pending whitespace, ignoring pending C4_ALWAYS_INLINE void _pend_none() noexcept @@ -359,10 +361,26 @@ private: Tree const* C4_RESTRICT m_tree; EmitOptions m_opts; - size_t m_col; - id_type m_depth; - id_type m_ilevel; - Pws_e m_pws; + size_t m_col; + id_type m_depth; + id_type m_ilevel; + Pws_e m_pws; + +private: + + enum : type_bits { + _styles_block_key = KEY_LITERAL|KEY_FOLDED, + _styles_block_val = VAL_LITERAL|VAL_FOLDED, + _styles_block = _styles_block_key|_styles_block_val, + _styles_flow_key = KEY_STYLE & ~_styles_block_key, + _styles_flow_val = VAL_STYLE & ~_styles_block_val, + _styles_flow = _styles_flow_key|_styles_flow_val, + _styles_squo = KEY_SQUO|VAL_SQUO, + _styles_dquo = KEY_DQUO|VAL_DQUO, + _styles_plain = KEY_PLAIN|VAL_PLAIN, + _styles_literal = KEY_LITERAL|VAL_LITERAL, + _styles_folded = KEY_FOLDED|VAL_FOLDED, + }; /** @endcond */ }; diff --git a/src/c4/yml/event_handler_tree.hpp b/src/c4/yml/event_handler_tree.hpp index 3f4aaa1e..7b3c6957 100644 --- a/src/c4/yml/event_handler_tree.hpp +++ b/src/c4/yml/event_handler_tree.hpp @@ -188,20 +188,25 @@ public: { _c4dbgp("ensure stream"); _set_root_as_stream(); - id_type first = m_tree->first_child(m_tree->root_id()); - _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()), m_tree, m_curr->node_id); - _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u, m_tree, m_curr->node_id); + const id_type root = m_tree->root_id(); + const id_type first = m_tree->first_child(root); + _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_stream(root), m_tree, root); + _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->num_children(root) == 1u, m_tree, root); if(m_tree->is_container(first) || m_tree->is_val(first)) { _c4dbgp("push!"); _push(); + #ifdef RYML_WITH_COMMENTS + m_tree->_p(root)->m_first_comment = NONE; + m_tree->_p(root)->m_last_comment = NONE; + #endif } else { _c4dbgp("tweak"); _push(); _remove_speculative(); - m_curr->node_id = m_tree->last_child(m_tree->root_id()); + m_curr->node_id = m_tree->last_child(root); m_curr->tr_data = m_tree->_p(m_curr->node_id); } } diff --git a/src/c4/yml/node_type.cpp b/src/c4/yml/node_type.cpp index c31fee9b..98cbcaff 100644 --- a/src/c4/yml/node_type.cpp +++ b/src/c4/yml/node_type.cpp @@ -159,8 +159,7 @@ bool scalar_style_query_plain(csubstr s) noexcept { return true; } - return s != ':' - && ( ! s.begins_with_any("-:?*&,'\"{}[]|>%#@`\r")) // @ and ` are reserved characters + return ( ! s.begins_with_any("-:?*&,'\"{}[]|>%#@`\r")) // @ and ` are reserved characters && ( ! s.ends_with_any(":#")) // make this check in the last place, as it has linear // complexity, while the previous ones are diff --git a/src/c4/yml/tree.cpp b/src/c4/yml/tree.cpp index 8ce5ceba..e1e2fad3 100644 --- a/src/c4/yml/tree.cpp +++ b/src/c4/yml/tree.cpp @@ -934,7 +934,7 @@ bool Tree::change_type(id_type node, NodeType type) return false; else if(type.is_val() && is_val(node)) return false; - d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type; + d->m_type = (d->m_type & (~(MAP|SEQ|VAL|CONTAINER_STYLE|KEY_STYLE|VAL_STYLE))) | type; remove_children(node); return true; } diff --git a/src_extra/c4/yml/extra/event_handler_ints.cpp b/src_extra/c4/yml/extra/event_handler_ints.cpp index b20cf2a3..7924116c 100644 --- a/src_extra/c4/yml/extra/event_handler_ints.cpp +++ b/src_extra/c4/yml/extra/event_handler_ints.cpp @@ -61,6 +61,40 @@ int32_t estimate_events_ints_size(csubstr src) return count; } +// ensure the ievt flags work despite being signed +namespace ievt { +static_assert((MASK & BSTR) == BSTR, "overflow?"); +static_assert((MASK & ESTR) == ESTR, "overflow?"); +static_assert((MASK & BDOC) == BDOC, "overflow?"); +static_assert((MASK & EDOC) == EDOC, "overflow?"); +static_assert((MASK & BMAP) == BMAP, "overflow?"); +static_assert((MASK & EMAP) == EMAP, "overflow?"); +static_assert((MASK & BSEQ) == BSEQ, "overflow?"); +static_assert((MASK & ESEQ) == ESEQ, "overflow?"); +static_assert((MASK & ANCH) == ANCH, "overflow?"); +static_assert((MASK & ALIA) == ALIA, "overflow?"); +static_assert((MASK & TAG_) == TAG_, "overflow?"); +static_assert((MASK & PLAI) == PLAI, "overflow?"); +static_assert((MASK & SQUO) == SQUO, "overflow?"); +static_assert((MASK & DQUO) == DQUO, "overflow?"); +static_assert((MASK & LITL) == LITL, "overflow?"); +static_assert((MASK & FOLD) == FOLD, "overflow?"); +static_assert((MASK & FLOW) == FLOW, "overflow?"); +static_assert((MASK & BLCK) == BLCK, "overflow?"); +static_assert((MASK & KEY_) == KEY_, "overflow?"); +static_assert((MASK & VAL_) == VAL_, "overflow?"); +static_assert((MASK & EXPL) == EXPL, "overflow?"); +static_assert((MASK & YAML) == YAML, "overflow?"); +static_assert((MASK & TAGD) == TAGD, "overflow?"); +static_assert((MASK & TAGV) == TAGV, "overflow?"); +static_assert((MASK & AREN) == AREN, "overflow?"); +static_assert((MASK & PSTR) == PSTR, "overflow?"); +static_assert((MASK & UNFILT) == UNFILT, "overflow?"); +static_assert((MASK & LAST) == LAST, "overflow?"); +static_assert((MASK & MASK) == MASK, "overflow?"); +static_assert((MASK & WSTR) == WSTR, "overflow?"); +} // namespace ievt + } // namespace extra } // namespace yml } // namespace c4 diff --git a/src_extra/c4/yml/extra/event_handler_ints.hpp b/src_extra/c4/yml/extra/event_handler_ints.hpp index cdf8ca6e..e37d5bab 100644 --- a/src_extra/c4/yml/extra/event_handler_ints.hpp +++ b/src_extra/c4/yml/extra/event_handler_ints.hpp @@ -43,13 +43,32 @@ using DataType = int32_t; /** enumeration of integer event bits. */ typedef enum : DataType { + // Structure flags + KEY_ = (1 << 0), ///< as key + VAL_ = (1 << 1), ///< as value + /// special flag to enable look-back in the event array. it + /// signifies that the previous event has a string, meaning that + /// the jump back to that event is 3 positions. without this flag it + /// would be impossible to jump to the previous event. + /// see also @ref WSTR + PSTR = (1 << 2), + /// IMPORTANT. Marks events whose string was placed in the + /// arena. This happens when the filtered string is larger than the + /// original string in the YAML code (eg from tags that resolve to + /// a larger string, or from "\L" or "\P" in double quotes, which + /// expand from two to three bytes). Because of this size + /// expansion, the filtered string cannot be placed in the original + /// source and needs to be placed in the arena. + AREN = (1 << 3), + // Event scopes - BEG_ = (1 << 0), ///< scope: begin - END_ = (1 << 1), ///< scope: end - SEQ_ = (1 << 2), ///< scope: seq - MAP_ = (1 << 3), ///< scope: map - DOC_ = (1 << 4), ///< scope: doc - STRM = (1 << 5), ///< scope: stream + BEG_ = (1 << 5), ///< scope: begin + END_ = (1 << 6), ///< scope: end + SEQ_ = (1 << 7), ///< scope: seq + MAP_ = (1 << 8), ///< scope: map + DOC_ = (1 << 9), ///< scope: doc + EXPL = (1 << 10), ///< `---` (with BDOC) or `...` (with EDOC) + STRM = (1 << 11), ///< scope: stream BSEQ = BEG_|SEQ_, ///< begin seq (+SEQ in test suite events) ESEQ = END_|SEQ_, ///< end seq (-SEQ in test suite events) BMAP = BEG_|MAP_, ///< begin map (+MAP in test suite events) @@ -60,58 +79,41 @@ typedef enum : DataType { EDOC = END_|DOC_, ///< end doc (-DOC in test suite events) // Single events - SCLR = (1 << 6), ///< scalar (=VAL in test suite events) - ALIA = (1 << 7), ///< *ref (reference) - ANCH = (1 << 8), ///< &anchor - TAG_ = (1 << 9), ///< !tag - - // Structure flags - KEY_ = (1 << 10), ///< as key - VAL_ = (1 << 11), ///< as value - EXPL = (1 << 12), ///< `---` (with BDOC) or `...` (with EDOC) + SCLR = (1 << 12), ///< scalar (=VAL in test suite events) + ALIA = (1 << 13), ///< *ref (reference) + ANCH = (1 << 14), ///< &anchor + TAG_ = (1 << 15), ///< !tag // Style flags - PLAI = (1 << 13), ///< scalar: plain - SQUO = (1 << 14), ///< scalar: single-quoted (') - DQUO = (1 << 15), ///< scalar: double-quoted ("") - LITL = (1 << 16), ///< scalar: block literal (|) - FOLD = (1 << 17), ///< scalar: block folded (>) - FLOW = (1 << 18), ///< container: flow: [] for seqs or {} for maps - BLCK = (1 << 19), ///< container: block + PLAI = (1 << 16), ///< scalar: plain + SQUO = (1 << 17), ///< scalar: single-quoted (') + DQUO = (1 << 18), ///< scalar: double-quoted ("") + LITL = (1 << 19), ///< scalar: block literal (|) + FOLD = (1 << 20), ///< scalar: block folded (>) + FLOW = (1 << 21), ///< container: flow: [] for seqs or {} for maps + BLCK = (1 << 22), ///< container: block // Directive flags - YAML = (1 << 20), ///< yaml directive: `\%YAML ` - TAGD = (1 << 21), ///< tag directive, name : `\%TAG .......` - TAGV = (1 << 22), ///< tag directive, value: `\%TAG ...... ` + YAML = (1 << 23), ///< yaml directive: `\%YAML ` + TAGD = (1 << 24), ///< tag directive, name : `\%TAG .......` + TAGV = (1 << 25), ///< tag directive, value: `\%TAG ...... ` - // Buffer flags - /// IMPORTANT. Marks events whose string was placed in the - /// arena. This happens when the filtered string is larger than the - /// original string in the YAML code (eg from tags that resolve to - /// a larger string, or from "\L" or "\P" in double quotes, which - /// expand from two to three bytes). Because of this size - /// expansion, the filtered string cannot be placed in the original - /// source and needs to be placed in the arena. - AREN = (1 << 23), - /// special flag to enable look-back in the event array. it - /// signifies that the previous event has a string, meaning that - /// the jump back to that event is 3 positions. without this flag it - /// would be impossible to jump to the previous event. - PSTR = (1 << 24), /// special flag to mark a scalar as unfiltered (when the parser /// is set not to filter). - UNFILT = (1 << 25), + UNFILT = (1 << 26), // Utility flags/masks /// the last flag defined above LAST = UNFILT, /// a mask of all bits in this enumeration MASK = (LAST << 1) - 1, - /// with string: mask of all the events that encode a string - /// following the event. in the event has a string. the next two - /// integers will provide respectively the string's offset and - /// length. See also @ref PSTR. + + /// WithSTRing: mask of all the events that encode a string + /// following the event. For such events, the next two integers + /// will provide respectively the string's offset and length. See + /// also @ref PSTR. WSTR = SCLR|ALIA|ANCH|TAG_|TAGD|TAGV|YAML, + } EventFlags; } // namespace ievt diff --git a/src_extra/c4/yml/extra/event_handler_testsuite.cpp b/src_extra/c4/yml/extra/event_handler_testsuite.cpp index 175d04b3..ad31897c 100644 --- a/src_extra/c4/yml/extra/event_handler_testsuite.cpp +++ b/src_extra/c4/yml/extra/event_handler_testsuite.cpp @@ -17,7 +17,7 @@ #ifndef _C4_YML_EXTRA_SCALAR_HPP_ #include "c4/yml/extra/scalar.hpp" #endif -#ifndef _C4_YML_EXTRA_SCALAR_HPP_ +#ifndef _C4_YML_EXTRA_STRING_HPP_ #include "c4/yml/extra/string.hpp" #endif diff --git a/test/test_emit.cpp b/test/test_emit.cpp index 96407c1f..500abfa5 100644 --- a/test/test_emit.cpp +++ b/test/test_emit.cpp @@ -234,28 +234,56 @@ TEST(emit_nested, basic) TEST(emit_block_seq, ambiguous_plain_emitted_as_squo) { - Tree t; - NodeRef r = t.rootref(); - r |= SEQ|BLOCK; - r[0] = ": odd"; - r[0] |= VAL_PLAIN; - r[1] = ":\todd"; - r[1] |= VAL_PLAIN; - EXPECT_EQ(emitrs_yaml(t), "- ': odd'\n- ':\todd'\n"); + EXPECT_EQ(scalar_style_query_plain(": odd"), false); + EXPECT_EQ(scalar_style_query_plain(":\todd"), false); + EXPECT_EQ(scalar_style_choose(": odd"), SCALAR_SQUO); + EXPECT_EQ(scalar_style_choose(":\todd"), SCALAR_SQUO); + { + Tree t; + NodeRef r = t.rootref(); + r |= SEQ|BLOCK; + r[0] = ": odd"; + r[0] |= VAL_PLAIN; + r[1] = ":\todd"; + r[1] |= VAL_PLAIN; + EXPECT_EQ(emitrs_yaml(t), "- : odd\n- :\todd\n"); + } + { + Tree t; + NodeRef r = t.rootref(); + r |= SEQ|BLOCK; + r[0] = ": odd"; + r[1] = ":\todd"; + EXPECT_FALSE(r[0].is_val_plain()); + EXPECT_FALSE(r[1].is_val_plain()); + EXPECT_EQ(emitrs_yaml(t), "- ': odd'\n- ':\todd'\n"); + } } TEST(emit_block_map, ambiguous_plain_emitted_as_squo) { - Tree t; - NodeRef r = t.rootref(); - r |= MAP|BLOCK; - r[0].set_key(": odd"); - r[0] = ": odd"; - r[0] |= KEY_PLAIN|VAL_PLAIN; - r[1].set_key(":\todd"); - r[1] = ":\todd"; - r[1] |= KEY_PLAIN|VAL_PLAIN; - EXPECT_EQ(emitrs_yaml(t), "': odd': ': odd'\n':\todd': ':\todd'\n"); + { + Tree t; + NodeRef r = t.rootref(); + r |= MAP|BLOCK; + r[0].set_key(": odd"); + r[0] = ": odd"; + r[1].set_key(":\todd"); + r[1] = ":\todd"; + EXPECT_EQ(emitrs_yaml(t), "': odd': ': odd'\n':\todd': ':\todd'\n"); + } + { + Tree t; + NodeRef r = t.rootref(); + r |= MAP|BLOCK; + r[0].set_key(": odd"); + r[0] = ": odd"; + r[0] |= KEY_PLAIN|VAL_PLAIN; + r[1].set_key(":\todd"); + r[1] = ":\todd"; + r[1] |= KEY_PLAIN|VAL_PLAIN; + EXPECT_EQ(emitrs_yaml(t), ": odd: : odd\n:\todd: :\todd\n"); + } } @@ -755,12 +783,8 @@ TEST(emit, empty_key_literal) test_emits(t, t.root_id(), expected, expected_json); } { - SCOPED_TRACE("nested"); - const Tree t = parse_in_arena(R"( -level1: - ? |- - : literal -)"); + SCOPED_TRACE("nested1"); + const Tree t = parse_in_arena("level1:\n ? |-\n : literal\n"); std::string expected = "level1:\n ? |-\n : literal\n"; std::string expected_json = "{\n \"level1\": {\n \"\": \"literal\"\n }\n}\n"; test_emits(t, t.root_id(), expected, expected_json); diff --git a/test/test_engine_4_anchor.cpp b/test/test_engine_4_anchor.cpp index 09834b82..dd7537cd 100644 --- a/test/test_engine_4_anchor.cpp +++ b/test/test_engine_4_anchor.cpp @@ -561,7 +561,7 @@ ENGINE_TEST(AnchorMapMapFlow, //----------------------------------------------------------------------------- -ENGINE_TEST(AnchorTagPlacement, +ENGINE_TEST(AnchorTagPlacement1, "- &a0 !b0 foo0: bar0\n" "- &a1 !b1\n" " foo1: bar1\n" @@ -576,14 +576,14 @@ ENGINE_TEST(AnchorTagPlacement, "\n" " foo4: bar4\n" , - "- !b0 &a0 foo0: bar0\n" - "- !b1 &a1\n" + "- &a0 !b0 foo0: bar0\n" + "- &a1 !b1\n" " foo1: bar1\n" "- &a2\n" " !b2 foo2: bar2\n" - "- !b3 &a3\n" + "- &a3 !b3\n" " foo3: bar3\n" - "- !b4 &a4\n" + "- &a4 !b4\n" " foo4: bar4\n" , "+STR\n" @@ -655,6 +655,100 @@ ENGINE_TEST(AnchorTagPlacement, ___(ps.end_stream()); } +ENGINE_TEST(AnchorTagPlacement2, + "- !b0 &a0 foo0: bar0\n" + "- !b1 &a1\n" + " foo1: bar1\n" + "- !b2\n" + " &a2 foo2: bar2\n" + "- !b3\n" + " &a3\n" + " foo3: bar3\n" + "- !b4\n" + "\n" + " &a4\n" + "\n" + " foo4: bar4\n" + , + "- &a0 !b0 foo0: bar0\n" + "- &a1 !b1\n" + " foo1: bar1\n" + "- !b2\n" + " &a2 foo2: bar2\n" + "- &a3 !b3\n" + " foo3: bar3\n" + "- &a4 !b4\n" + " foo4: bar4\n" + , + "+STR\n" + "+DOC\n" + "+SEQ\n" + "+MAP\n" + "=VAL &a0 :foo0\n" + "=VAL :bar0\n" + "-MAP\n" + "+MAP &a1 \n" + "=VAL :foo1\n" + "=VAL :bar1\n" + "-MAP\n" + "+MAP \n" + "=VAL &a2 :foo2\n" + "=VAL :bar2\n" + "-MAP\n" + "+MAP &a3 \n" + "=VAL :foo3\n" + "=VAL :bar3\n" + "-MAP\n" + "+MAP &a4 \n" + "=VAL :foo4\n" + "=VAL :bar4\n" + "-MAP\n" + "-SEQ\n" + "-DOC\n" + "-STR\n") +{ + ___(ps.begin_stream()); + ___(ps.begin_doc()); + ___(ps.begin_seq_val_block()); + ___(ps.begin_map_val_block()); + ___(ps.set_key_anchor("a0")); + ___(ps.set_key_tag("!b0")); + ___(ps.set_key_scalar_plain("foo0")); + ___(ps.set_val_scalar_plain("bar0")); + ___(ps.end_map_block()); + ___(ps.add_sibling()); + ___(ps.set_val_anchor("a1")); + ___(ps.set_val_tag("!b1")); + ___(ps.begin_map_val_block()); + ___(ps.set_key_scalar_plain("foo1")); + ___(ps.set_val_scalar_plain("bar1")); + ___(ps.end_map_block()); + ___(ps.add_sibling()); + ___(ps.set_val_tag("!b2")); + ___(ps.begin_map_val_block()); + ___(ps.set_key_anchor("a2")); + ___(ps.set_key_scalar_plain("foo2")); + ___(ps.set_val_scalar_plain("bar2")); + ___(ps.end_map_block()); + ___(ps.add_sibling()); + ___(ps.set_val_anchor("a3")); + ___(ps.set_val_tag("!b3")); + ___(ps.begin_map_val_block()); + ___(ps.set_key_scalar_plain("foo3")); + ___(ps.set_val_scalar_plain("bar3")); + ___(ps.end_map_block()); + ___(ps.add_sibling()); + ___(ps.set_val_anchor("a4")); + ___(ps.set_val_tag("!b4")); + ___(ps.begin_map_val_block()); + ___(ps.set_key_scalar_plain("foo4")); + ___(ps.set_val_scalar_plain("bar4")); + ___(ps.end_map_block()); + ___(ps.end_seq_block()); + ___(ps.end_doc()); + ___(ps.end_stream()); +} + ENGINE_TEST(AnchorMapMapSuckerPunch, "!mymap &mymap\n" @@ -684,23 +778,23 @@ ENGINE_TEST(AnchorMapMapSuckerPunch, "bru: &wtf\n" " foo\n" , - "!mymap &mymap\n" - "!footag &fooanch foo: &seq\n" + "&mymap !mymap\n" + "&fooanch !footag foo: &seq\n" " &key1 key1: &val1 val1\n" " &key2 key2: &val2 val2\n" - "!bartag &baranch bar: !a &map2\n" - " !b &key10 key10: !c &val10 val10\n" - " !b &key20 key20: !c &val20 val20\n" + "&baranch !bartag bar: &map2 !a\n" + " &key10 !b key10: &val10 !c val10\n" + " &key20 !b key20: &val20 !c val20\n" " key10: 20\n" - "!baztag &bazanch baz: !a &map2\n" - " !b &key10 key10: !c &val10 val10\n" - " !b &key20 key20: !c &val20 val20\n" + "&bazanch !baztag baz: &map2 !a\n" + " &key10 !b key10: &val10 !c val10\n" + " &key20 !b key20: &val20 !c val20\n" " key10: 20\n" "brr: &map2\n" " !a foo: bar\n" "bra: &map2\n" " !a foo: bar\n" - "bre: !a &map2\n" + "bre: &map2 !a\n" " foo: bar\n" "bru: &wtf foo\n" , @@ -880,23 +974,24 @@ ENGINE_TEST(AnchorSeqMapSuckerPunch, " foo: bar\n" "- &wtf\n" " foo\n" - " ", + " " + , "&seq\n" "- &key1 key1: &val1 val1\n" " &key2 key2: &val2 val2\n" - "- !a &map2a\n" - " !b &key10 key10: &val10 val10\n" + "- &map2a !a\n" + " &key10 !b key10: &val10 val10\n" " &key20 key20: &val20 val20\n" " key10: 20\n" - "- !a &map2x\n" - " !b &key10 key10: &val10 val10\n" + "- &map2x !a\n" + " &key10 !b key10: &val10 val10\n" " &key20 key20: &val20 val20\n" " key10: 20\n" "- &map2y\n" " !a foo: bar\n" "- &map2z\n" " !a foo: bar\n" - "- !a &map2u\n" + "- &map2u !a\n" " foo: bar\n" "- &wtf foo\n" , diff --git a/test/test_engine_5_tag.cpp b/test/test_engine_5_tag.cpp index 4bc1b1a5..f1f5ce4b 100644 --- a/test/test_engine_5_tag.cpp +++ b/test/test_engine_5_tag.cpp @@ -1131,8 +1131,6 @@ ENGINE_TEST(TagTestSuiteUGM3, ENGINE_TEST(TagTestSuiteUKK6_02_0, "!" , - "!\n" - , "+STR\n" "+DOC\n" "=VAL :\n" @@ -1142,7 +1140,7 @@ ENGINE_TEST(TagTestSuiteUKK6_02_0, ___(ps.begin_stream()); ___(ps.begin_doc()); ___(ps.set_val_tag("!")); - ___(ps.set_val_scalar_plain({})); + ___(ps.set_val_scalar_plain_empty()); ___(ps.end_doc()); ___(ps.end_stream()); }