comments wip

This commit is contained in:
Joao Paulo Magalhaes
2025-11-06 10:14:31 +00:00
parent 5367972793
commit 6c440614ac
31 changed files with 5869 additions and 33 deletions

View File

@@ -13,6 +13,7 @@ c4_project(VERSION 0.10.0 STANDALONE
#-------------------------------------------------------
option(RYML_WITH_TAB_TOKENS "Enable parsing of tabs after ':' and '-'. This is costly and disabled by default." OFF)
option(RYML_WITH_COMMENTS "Enable parsing of comments. This is costly and disabled by default." OFF)
option(RYML_DEFAULT_CALLBACKS "Enable ryml's default implementation of callbacks: allocate(), free(), error()" ON)
if(RYML_DEFAULT_CALLBACKS)
option(RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS "Throw exceptions instead of calling abort in the default error handler provided by ryml" OFF)
@@ -41,6 +42,7 @@ c4_add_library(ryml
c4/yml/detail/dbgprint.hpp
c4/yml/detail/print.hpp
c4/yml/detail/stack.hpp
c4/yml/comment_type.hpp
c4/yml/common.hpp
c4/yml/common.cpp
c4/yml/emit.def.hpp
@@ -90,6 +92,10 @@ if(RYML_WITH_TAB_TOKENS)
target_compile_definitions(ryml PUBLIC RYML_WITH_TAB_TOKENS)
endif()
if(RYML_WITH_COMMENTS)
target_compile_definitions(ryml PUBLIC RYML_WITH_COMMENTS)
endif()
if(NOT RYML_DEFAULT_CALLBACKS)
target_compile_definitions(ryml PRIVATE RYML_NO_DEFAULT_CALLBACKS)
else()

162
src/c4/yml/comment_type.hpp Normal file
View File

@@ -0,0 +1,162 @@
#ifndef C4_YML_COMMENT_TYPE_HPP_
#define C4_YML_COMMENT_TYPE_HPP_
#include <stdint.h>
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_COMMON_HPP_
#include "c4/yml/common.hpp"
#endif
namespace c4 {
namespace yml {
/** @addtogroup doc_node_type
*
* @{
*/
using comment_data_type = uint32_t;
/**
*
*
*
*
* Flow seq:
* ```yaml
* # LEADING
* [
* # LEADING
* val1, # TRAILING
* # LEADING
* val2 # TRAILING
* ] # TRAILING
* ```
*
* Flow map:
* ```yaml
* {
* # LEADING
* key1: val1, # TRAILING
* # LEADING
* key2: val2 # TRAILING
* }
* ```
*
* Block seq:
* ```yaml
* # LEADING
* - val1 # TRAILING
* # LEADING
* - val2 # TRAILING
* ```
*
* Block map:
* ```yaml
* # LEADING
* key1: val1 # TRAILING
* # LEADING
* key2: val2 # TRAILING
* ```
*
*
* ```yaml
* --- # Flow map TRAILING (node 4)
* # LEADING (container node)
* { # VAL_TRAILING_OPEN (container node)
*
* # LEADING
* key: val, # TRAILING
*
* # LEADING
* key: # COLON_TRAILING
* # VAL_LEADING
* val, # TRAILING
* # VAL_FOOTER
*
* # LEADING
* key # KEY_TRAILING
* # KEY_FOOTER
* : # COLON_TRAILING
* # VAL_LEADING
* val, # TRAILING
*
* # LEADING
* key # KEY_TRAILING
* # KEY_FOOTER
* : # COLON_TRAILING
* # VAL_LEADING
* val # VAL_TRAILING
* # COMMA_LEADING
* , # TRAILING
*
* # 1 LEADING
* # 2 KEY_TAG_LEADING
* !keytag # 3 KEY_TAG_TRAILING
* # 4 KEY_ANCHOR_LEADING
* &keyanchor # 5 KEY_ANCHOR_TRAILING
* # 6 KEY_LEADING
* key # 7 KEY_TRAILING
* # 8 COLON_LEADING
* : # 9 COLON_TRAILING
* # 10 VAL_LEADING
* # 11 VAL_TAG_LEADING
* !valtag # 12 VAL_TAG_TRAILING
* # 13 VAL_ANCHOR_LEADING
* &valanchor # 14 VAL_ANCHOR_TRAILING
* # 15 VAL_LEADING2
* val # 16 TRAILING
* # 17 FOOTER (child node)
* } # TRAILING (container node)
* # VAL_FOOTER (container node)
* ```
*/
typedef enum : comment_data_type {
#define _RYML_DEFINE_COMMENTS(macro) \
/* STREAM */ \
macro(DOC_TRAILING, 0) /* trailing --- */ \
macro(LEADING, 1) /* leading, GENERAL */ \
macro(KEY_TRAILING_QMRK, 2) /* trailing ? */ \
macro(KEY_FOOTER_QMRK, 3) /* footer ? */ \
macro(KEY_ANCHOR_LEADING, 4) \
macro(KEY_ANCHOR_TRAILING, 5) \
macro(KEY_TAG_LEADING, 6) \
macro(KEY_TAG_TRAILING, 7) \
macro(KEY_LEADING, 8) \
macro(KEY_BRACKET_TRAILING, 9) \
macro(KEY_TRAILING, 10) \
macro(KEY_FOOTER, 11) \
macro(COLON_LEADING, 12) \
macro(COLON_TRAILING, 13) \
macro(VAL_DASH_TRAILING, 14) \
macro(VAL_LEADING, 15) \
macro(VAL_ANCHOR_LEADING, 16) \
macro(VAL_ANCHOR_TRAILING, 17) \
macro(VAL_TAG_LEADING, 18) \
macro(VAL_TAG_TRAILING, 19) \
macro(VAL_LEADING2, 20) \
macro(VAL_BRACKET_TRAILING, 21) \
macro(VAL_BRACKET_LEADING, 22) \
macro(VAL_TRAILING, 23) \
macro(COMMA_LEADING, 24) \
macro(TRAILING, 25) \
macro(FOOTER, 26)
#define _c4comm(comm_symbol, bit) COMM_##comm_symbol = (UINT32_C(1) << UINT32_C(bit)),
_RYML_DEFINE_COMMENTS(_c4comm)
_c4comm(LAST_, 26)
COMM_ANY = (COMM_LAST_ << 1u) - 1u,
COMM_NONE = 0,
#undef _c4comm
} CommentType_e;
/** @} */
} // namespace yml
} // namespace c4
#endif // RYML_WITH_COMMENTS
#endif /* C4_YML_COMMENT_TYPE_HPP_ */

View File

@@ -319,6 +319,9 @@ private:
SCALAR_FILTERING = (1u << 0u),
LOCATIONS = (1u << 1u),
DETECT_FLOW_ML = (1u << 2u),
#ifdef RYML_WITH_COMMENTS
WITH_COMMENTS = (1u << 3u),
#endif
DEFAULTS = SCALAR_FILTERING|DETECT_FLOW_ML,
} Flags_e;
@@ -387,6 +390,29 @@ public:
C4_ALWAYS_INLINE bool scalar_filtering() const noexcept { return (flags & SCALAR_FILTERING); }
/** @} */
public:
#ifdef RYML_WITH_COMMENTS
/** @name comment parsing */
/** @{ */
/** enable/disable comment parsing. available only when @ref
* RYML_WITH_COMMENTS is defined */
ParserOptions& with_comments(bool enabled) noexcept
{
if(enabled)
flags |= WITH_COMMENTS;
else
flags &= ~WITH_COMMENTS;
return *this;
}
/** query comments parsing status. available only when @ref
* RYML_WITH_COMMENTS is defined */
C4_ALWAYS_INLINE bool with_comments() const noexcept { return (flags & WITH_COMMENTS); }
/** @} */
#endif // RYML_WITH_COMMENTS
};
@@ -583,6 +609,16 @@ inline csubstr _c4prc(const char &C4_RESTRICT c) // pass by reference!
}
}
#if defined(RYML_WITH_COMMENTS)
#define _RYML_WITH_COMMENTS(...) __VA_ARGS__
#define _RYML_WITHOUT_COMMENTS(...)
#define _RYML_WITH_OR_WITHOUT_COMMENTS(with, without) with
#else
#define _RYML_WITH_COMMENTS(...)
#define _RYML_WITHOUT_COMMENTS(...) __VA_ARGS__
#define _RYML_WITH_OR_WITHOUT_COMMENTS(with, without) without
#endif
/// @endcond
C4_SUPPRESS_WARNING_GCC_POP

View File

@@ -106,7 +106,24 @@ inline C4_NO_INLINE id_type print_node(Tree const& p, id_type node, int level, i
printf(" %c%.*s%c", code, (int)v.len, v.str, code);
}
printf(" (%zu sibs)", (size_t)p.num_siblings(node));
#ifdef RYML_WITH_COMMENTS
if(p.comment(node))
{
printf(" COMM[");
NodeData const* n = p._p(node);
id_type ccount = 0;
for(id_type cid = n->m_first_comment; cid != NONE; cid = p.m_comments_buf[cid].m_next)
{
CommentData const& comm = p.m_comments_buf[cid];
if(ccount++) printf("|");
if(false) ;
#define _c4commtostr(sym, bit) else if(comm.m_type & COMM_##sym) printf(#sym);
_RYML_DEFINE_COMMENTS(_c4commtostr)
#undef _c4commtpstr
}
printf("]");
}
#endif
++count;
if(!p.is_container(node))

View File

@@ -31,6 +31,8 @@ substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& tree, id_type id, b
m_depth = 0;
m_ilevel = 0;
m_pws = _PWS_NONE;
_RYML_WITH_COMMENTS(m_wsonly = true);
_RYML_WITH_COMMENTS(m_comm_state.clear());
if(type == EMIT_YAML)
_emit_yaml(id);
else if(type == EMIT_JSON)
@@ -175,7 +177,7 @@ void Emitter<Writer>::_visit_stream(id_type id)
_top_close_entry(child);
if(m_tree->is_val(child))
{
if(m_tree->type(child) & VALNIL)
if((m_tree->type(child) & VALNIL) _RYML_WITH_COMMENTS( && !m_tree->comment(child)))
_pend_newl();
}
else if(m_tree->is_container(child))
@@ -189,6 +191,16 @@ void Emitter<Writer>::_visit_stream(id_type id)
}
}
--m_depth;
#ifdef RYML_WITH_COMMENTS
CommentData const* comm = _comm_get(id, COMM_TRAILING);
if(comm)
{
_write_pws_and_pend(_PWS_NONE);
_write("...");
_write_comm_trailing(comm);
}
_write_comm_leading(id, COMM_FOOTER);
#endif
}
@@ -287,21 +299,28 @@ template<class Writer>
void Emitter<Writer>::_top_open_entry(id_type node)
{
NodeType ty = m_tree->type(node);
_RYML_WITH_COMMENTS(_comm_push());
if(ty.is_doc() && !m_tree->is_root(node))
{
_write("---");
_pend_space();
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_DOC_TRAILING));
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_LEADING));
if(ty.has_val_anchor())
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_ANCHOR_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->val_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_ANCHOR_TRAILING));
}
if(ty.has_val_tag())
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_TAG_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->val_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_TAG_TRAILING));
}
if(m_pws == _PWS_SPACE)
{
@@ -325,6 +344,14 @@ void Emitter<Writer>::_top_open_entry(id_type node)
template<class Writer>
void Emitter<Writer>::_top_close_entry(id_type node)
{
#ifdef RYML_WITH_COMMENTS
if(!m_tree->is_stream(node)) // streams are handled in _write_stream()
{
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_TRAILING));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_FOOTER));
}
_comm_pop();
#endif
if(m_tree->is_val(node) && !(m_tree->type(node) & VALNIL))
{
_pend_newl();
@@ -339,17 +366,24 @@ void Emitter<Writer>::_flow_seq_open_entry(id_type node)
{
NodeType ty = m_tree->type(node);
_write_pws_and_pend(_PWS_NONE);
_RYML_WITH_COMMENTS(_comm_push());
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_LEADING));
if(ty & VALANCH)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_ANCHOR_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->val_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_ANCHOR_TRAILING));
}
if(ty & VALTAG)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_TAG_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->val_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_TAG_TRAILING));
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING2));
}
@@ -361,17 +395,24 @@ void Emitter<Writer>::_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);
_RYML_WITH_COMMENTS(_comm_push());
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_LEADING));
if(ty & KEYANCH)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_KEY_ANCHOR_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write("&");
_write(m_tree->key_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_KEY_ANCHOR_TRAILING));
}
if(ty & KEYTAG)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_KEY_TAG_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->key_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_KEY_TAG_TRAILING));
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_KEY_LEADING));
if(ty & KEYREF)
{
_write_pws_and_pend(_PWS_SPACE);
@@ -385,19 +426,28 @@ void Emitter<Writer>::_flow_map_open_entry(id_type node)
ty |= scalar_style_choose(key) & (NodeType_e)_styles_flow_key;
_flow_write_scalar(key, ty & (NodeType_e)_styles_flow_key);
}
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_KEY_TRAILING));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_COLON_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write(':');
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_COLON_TRAILING));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING));
if(ty & VALANCH)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_ANCHOR_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->val_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_ANCHOR_TRAILING));
}
if(ty & VALTAG)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_TAG_LEADING));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->val_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_TAG_TRAILING));
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING2));
}
@@ -406,21 +456,24 @@ void Emitter<Writer>::_flow_map_open_entry(id_type node)
template<class Writer>
void Emitter<Writer>::_flow_close_entry_sl(id_type node, id_type last_sibling)
{
if(node != last_sibling)
_RYML_WITH_COMMENTS(CommentData const *commvt = _comm_get(node, COMM_VAL_TRAILING));
_RYML_WITH_COMMENTS(CommentData const *commcl = _comm_get(node, COMM_COMMA_LEADING));
if(node != last_sibling _RYML_WITH_COMMENTS(|| commvt || commcl))
{
_RYML_WITH_COMMENTS(if(commvt) _write_comm_trailing(commvt));
_RYML_WITH_COMMENTS(if(commcl) _write_comm_leading(commcl));
_write_pws_and_pend(_PWS_NONE);
_write(',');
}
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_TRAILING));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_FOOTER));
_RYML_WITH_COMMENTS(_comm_pop());
}
template<class Writer>
void Emitter<Writer>::_flow_close_entry_ml(id_type node, id_type last_sibling)
{
if(node != last_sibling)
{
_write_pws_and_pend(_PWS_NONE);
_write(',');
}
_flow_close_entry_sl(node, last_sibling);
_pend_newl();
}
@@ -432,21 +485,29 @@ void Emitter<Writer>::_blck_seq_open_entry(id_type node)
{
NodeType ty = m_tree->type(node);
_write_pws_and_pend(_PWS_NONE);
_RYML_WITH_COMMENTS(_comm_push());
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_LEADING));
_write_pws_and_pend(_PWS_SPACE); // pend the space after the following dash
_write('-');
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_DASH_TRAILING, /*indent_extra*/true));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING, /*indent_extra*/true));
bool has_tag_or_anchor = false;
if(ty & VALANCH)
{
has_tag_or_anchor = true;
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_ANCHOR_LEADING, /*indent_extra*/true));
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->val_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_ANCHOR_TRAILING, /*indent_extra*/true));
}
if(ty & VALTAG)
{
has_tag_or_anchor = true;
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_TAG_LEADING, /*indent_extra*/true));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->val_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_TAG_TRAILING, /*indent_extra*/true));
}
if(has_tag_or_anchor && ty.is_container())
{
@@ -455,6 +516,7 @@ void Emitter<Writer>::_blck_seq_open_entry(id_type node)
if((ty & BLOCK) && m_tree->has_children(node))
_pend_newl();
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING2, /*indent_extra*/true));
}
@@ -463,10 +525,89 @@ void Emitter<Writer>::_blck_seq_open_entry(id_type node)
template<class Writer>
void Emitter<Writer>::_blck_write_qmrk(id_type node, csubstr key, type_bits ty, bool has_qmrk_comments)
{
#ifndef RYML_WITH_COMMENTS
(void)node;
(void)key;
(void)ty;
(void)has_qmrk_comments;
#else
#define _ryml_write_comm_leading_and_nest(node, commtype) \
do { \
CommentData const* comm = _comm_get(node, commtype); \
if(comm) \
{ \
if(!nested) \
{ \
nested = true; \
++m_ilevel; \
} \
_write_comm_leading(comm); \
} \
} while(0)
#define _ryml_write_comm_trailing_and_nest(node, commtype) \
do { \
if(_write_comm_trailing(node, commtype)) \
{ \
if(!nested) \
{ \
nested = true; \
++m_ilevel; \
} \
} \
} while(0)
bool nested = false;
_write_pws_and_pend(_PWS_SPACE);
_write('?');
_ryml_write_comm_trailing_and_nest(node, COMM_KEY_TRAILING_QMRK);
if(ty & KEYANCH)
{
_ryml_write_comm_leading_and_nest(node, COMM_KEY_ANCHOR_LEADING);
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->key_anchor(node));
_ryml_write_comm_trailing_and_nest(node, COMM_KEY_ANCHOR_TRAILING);
}
if(ty & KEYTAG)
{
_ryml_write_comm_leading_and_nest(node, COMM_KEY_TAG_LEADING);
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->key_tag(node));
_ryml_write_comm_trailing_and_nest(node, COMM_KEY_TAG_TRAILING);
}
_ryml_write_comm_leading_and_nest(node, COMM_KEY_LEADING);
if(!(ty & KEYREF))
{
_write_pws_and_pend(_PWS_NEWL);
if(!(ty & KEY_STYLE))
ty &= (scalar_style_choose(key) & KEY_STYLE);
if(!(ty & _styles_block_key) || !has_qmrk_comments || nested)
{
_blck_write_scalar(key, ty & KEY_STYLE);
}
else
{
++m_ilevel;
_blck_write_scalar(key, ty & KEY_STYLE);
--m_ilevel;
}
}
else
{
_write_pws_and_pend(_PWS_SPACE);
_write_ref(key);
}
// make sure trailing comments are not printed directly after block scalars
if(!(ty & _styles_block_key))
_ryml_write_comm_trailing_and_nest(node, COMM_KEY_TRAILING);
else
_ryml_write_comm_leading_and_nest(node, COMM_KEY_TRAILING);
_ryml_write_comm_leading_and_nest(node, COMM_KEY_FOOTER);
if(nested)
--m_ilevel;
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_COLON_LEADING));
#undef _ryml_write_comm_leading_and_nest
#undef _ryml_write_comm_trailing_and_nest
#endif
}
@@ -481,6 +622,8 @@ void Emitter<Writer>::_blck_map_open_entry(id_type node)
if(!(ty & (KEY_STYLE|KEYREF)))
ty |= (scalar_style_choose(key) & KEY_STYLE);
_write_pws_and_pend(_PWS_NONE);
_RYML_WITH_COMMENTS(_comm_push());
#ifndef RYML_WITH_COMMENTS
if(ty & KEYANCH)
{
_write_pws_and_pend(_PWS_SPACE);
@@ -512,18 +655,73 @@ void Emitter<Writer>::_blck_map_open_entry(id_type node)
_pend_newl();
}
}
#else
enum : comment_data_type {
_comms_requiring_qmrk =
COMM_KEY_TRAILING_QMRK
| COMM_KEY_FOOTER_QMRK
| COMM_KEY_TAG_LEADING
| COMM_KEY_TAG_TRAILING
| COMM_KEY_ANCHOR_LEADING
| COMM_KEY_ANCHOR_TRAILING
| COMM_KEY_LEADING
| COMM_KEY_TRAILING
| COMM_KEY_FOOTER
| COMM_COLON_LEADING
};
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_LEADING));
// should we use an explicit key (with leading '?')?
bool has_qmrk_comments = m_opts.comments() && !!m_tree->comment(node, _comms_requiring_qmrk);
if(!((ty & _styles_block_key) || has_qmrk_comments))
{
if(ty & KEYANCH)
{
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->key_anchor(node));
}
if(ty & KEYTAG)
{
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->key_tag(node));
}
if(!(ty & KEYREF))
{
if(!(ty & KEY_STYLE))
ty &= (scalar_style_choose(key) & KEY_STYLE);
_write_pws_and_pend(_PWS_NONE);
_blck_write_scalar(key, ty & KEY_STYLE);
}
else
{
_write_pws_and_pend(_PWS_SPACE);
_write_ref(key);
}
}
else
{
_blck_write_qmrk(node, key, ty, has_qmrk_comments);
}
#endif
_write_pws_and_pend(_PWS_SPACE); // pend the space after the colon
_write(':');
_RYML_WITH_COMMENTS(bool indent_extra = (ty & VAL));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_COLON_TRAILING, indent_extra));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING, indent_extra));
if(ty & VALANCH)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_ANCHOR_LEADING, indent_extra));
_write_pws_and_pend(_PWS_SPACE);
_write('&');
_write(m_tree->val_anchor(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_ANCHOR_TRAILING, indent_extra));
}
if(ty & VALTAG)
{
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_TAG_LEADING, indent_extra));
_write_pws_and_pend(_PWS_SPACE);
_write_tag(m_tree->val_tag(node));
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_TAG_TRAILING, indent_extra));
}
if(ty.is_container() && m_tree->has_children(node))
{
@@ -532,6 +730,7 @@ void Emitter<Writer>::_blck_map_open_entry(id_type node)
if(ty.is_block())
_pend_newl();
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_LEADING2, indent_extra));
}
@@ -541,6 +740,9 @@ template<class Writer>
void Emitter<Writer>::_blck_close_entry(id_type node)
{
(void)node;
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_TRAILING));
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_FOOTER));
_RYML_WITH_COMMENTS(_comm_pop());
_pend_newl();
}
@@ -644,6 +846,7 @@ void Emitter<Writer>::_visit_flow_sl_seq(id_type node)
{
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
_write('[');
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_BRACKET_TRAILING));
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);
@@ -672,6 +875,7 @@ void Emitter<Writer>::_visit_flow_sl_seq(id_type node)
}
_flow_close_entry_sl(child, last);
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_BRACKET_LEADING));
_write(']');
}
@@ -684,6 +888,7 @@ void Emitter<Writer>::_visit_flow_ml_seq(id_type node)
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_seq(node), m_tree, node);
_write('[');
_pend_newl();
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_BRACKET_TRAILING));
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))
{
@@ -713,6 +918,7 @@ void Emitter<Writer>::_visit_flow_ml_seq(id_type node)
}
_flow_close_entry_ml(child, last);
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_BRACKET_LEADING));
if(m_opts.indent_flow_ml()) --m_ilevel;
_write_pws_and_pend(_PWS_NONE);
_write(']');
@@ -726,6 +932,7 @@ void Emitter<Writer>::_visit_flow_sl_map(id_type node)
{
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
_write('{');
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_BRACKET_TRAILING));
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);
@@ -754,6 +961,7 @@ void Emitter<Writer>::_visit_flow_sl_map(id_type node)
}
_flow_close_entry_sl(child, last);
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_BRACKET_LEADING));
_write_pws_and_pend(_PWS_NONE);
_write('}');
}
@@ -767,6 +975,7 @@ void Emitter<Writer>::_visit_flow_ml_map(id_type node)
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_map(node), m_tree, node);
_write('{');
_pend_newl();
_RYML_WITH_COMMENTS(_write_comm_trailing(node, COMM_VAL_BRACKET_TRAILING));
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))
{
@@ -796,6 +1005,7 @@ void Emitter<Writer>::_visit_flow_ml_map(id_type node)
}
_flow_close_entry_ml(child, last);
}
_RYML_WITH_COMMENTS(_write_comm_leading(node, COMM_VAL_BRACKET_LEADING));
if(m_opts.indent_flow_ml()) --m_ilevel;
_write_pws_and_pend(_PWS_NONE);
_write('}');
@@ -1256,6 +1466,132 @@ void Emitter<Writer>::_write_scalar_plain(csubstr s, id_type ilevel)
}
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
template<class Writer>
void Emitter<Writer>::_write_comm(csubstr s, id_type indentation)
{
_write('#');
size_t pos = 0; // last character that was already written
for(size_t i = 0; i < s.len; ++i)
{
if(s.str[i] == '\n')
{
csubstr sub = s.range(pos, i);
_write(sub); // write everything up to (including) this newline
_newl();
pos = i + 1;
_write(' ', indentation); // _indent() is for level, but we have explicit indentation
_write('#');
}
}
// write remaining characters at the end of the string
if(pos < s.len)
{
csubstr sub = s.sub(pos);
_write(sub);
}
}
template<class Writer>
void Emitter<Writer>::_write_comm_leadspace(csubstr s, id_type indentation)
{
_write('#');
size_t pos = 0; // last character that was already written
for(size_t i = 0; i < s.len; ++i)
{
if(s.str[i] == '\n')
{
csubstr sub = s.range(pos, i);
if(sub.len && !sub.begins_with(' '))
_write(' ');
_write(sub); // write everything up to (including) this newline
_newl();
pos = i + 1;
_write(' ', indentation); // _indent() is for level, but we have explicit indentation
_write('#');
}
}
// write remaining characters at the end of the string
if(pos < s.len)
{
csubstr sub = s.sub(pos);
if(sub.len && !sub.begins_with(' '))
_write(' ');
_write(sub);
}
}
template<class Writer>
void Emitter<Writer>::_write_comm_trailing(CommentData const* comm)
{
_write(' ');
if(!m_opts.comments_add_leading_space())
_write_comm(comm->m_text, m_col);
else
_write_comm_leadspace(comm->m_text, m_col);
_pend_newl();
}
template<class Writer>
void Emitter<Writer>::_write_comm_leading(CommentData const* comm)
{
if(!m_wsonly)
{
_newl();
_indent(m_ilevel);
}
if(!m_opts.comments_add_leading_space())
_write_comm(comm->m_text, m_col);
else
_write_comm_leadspace(comm->m_text, m_col);
_pend_newl();
}
template<class Writer>
CommentData const* Emitter<Writer>::_comm_get(id_type node, CommentType_e type, bool indent_extra)
{
if(!m_opts.comments())
return nullptr;
CommState *result = &m_comm_state.top();
#ifdef RYML_USE_ASSERT // ensure the queries are in order of CommentType
_RYML_ASSERT_VISIT_(m_tree->callbacks(), type >= result->latest_query, m_tree, node);
result->latest_query = type;
#endif
result->comm = m_tree->comment(node, result->latest, type);
if(result->comm)
{
result->latest = result->comm;
if(indent_extra && !result->extra_indentation)
{
result->extra_indentation = 1;
++m_ilevel;
}
}
return result->comm;
}
template<class Writer>
CommentData const* Emitter<Writer>::_write_comm_trailing(id_type node, CommentType_e type, bool indent_extra)
{
CommentData const* comm = _comm_get(node, type, indent_extra);
if(comm)
_write_comm_trailing(comm);
return comm;
}
template<class Writer>
CommentData const* Emitter<Writer>::_write_comm_leading(id_type node, CommentType_e type, bool indent_extra)
{
CommentData const* comm = _comm_get(node, type, indent_extra);
if(comm)
_write_comm_leading(comm);
return comm;
}
#endif // RYML_WITH_COMMENTS
//-----------------------------------------------------------------------------
template<class Writer>

View File

@@ -16,6 +16,13 @@
#endif
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_DETAIL_STACK_HPP_
#include "./detail/stack.hpp"
#endif
#endif
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
@@ -64,10 +71,12 @@ public:
EMIT_NONROOT_DASH = 1u << 1u,
EMIT_NONROOT_MARKUP = EMIT_NONROOT_KEY|EMIT_NONROOT_DASH,
INDENT_FLOW_ML = 1u << 2u,
JSON_ERR_ON_TAG = 1u << 3u,
JSON_ERR_ON_ANCHOR = 1u << 4u,
COMMENTS = 1u << 3u, ///< enable commments in emitted code
COMMENTS_ADD_LEADING_SPACE = 1u << 4u, ///< ensure every comment # is followed by a space, even if the comment does not start with space
JSON_ERR_ON_TAG = 1u << 5u,
JSON_ERR_ON_ANCHOR = 1u << 6u,
_JSON_ERR_MASK = JSON_ERR_ON_TAG|JSON_ERR_ON_ANCHOR,
DEFAULT_FLAGS = EMIT_NONROOT_KEY|INDENT_FLOW_ML,
DEFAULT_FLAGS = EMIT_NONROOT_KEY|INDENT_FLOW_ML|COMMENTS|COMMENTS_ADD_LEADING_SPACE,
} EmitOptionFlags_e;
public:
@@ -82,6 +91,12 @@ public:
C4_ALWAYS_INLINE bool emit_nonroot_dash() const noexcept { return (m_option_flags & EMIT_NONROOT_DASH) != 0; }
EmitOptions& emit_nonroot_dash(bool enabled) noexcept { m_option_flags = (EmitOptionFlags_e)(enabled ? (m_option_flags | EMIT_NONROOT_DASH) : (m_option_flags & ~EMIT_NONROOT_DASH)); return *this; }
C4_ALWAYS_INLINE bool comments() const noexcept { return (m_option_flags & COMMENTS) != 0; }
EmitOptions& comments(bool enabled) noexcept { m_option_flags = (EmitOptionFlags_e)(enabled ? (m_option_flags | COMMENTS) : (m_option_flags & ~COMMENTS)); return *this; }
C4_ALWAYS_INLINE bool comments_add_leading_space() const noexcept { return (m_option_flags & COMMENTS_ADD_LEADING_SPACE) != 0; }
EmitOptions& comments_add_leading_space(bool enabled) noexcept { m_option_flags = (EmitOptionFlags_e)(enabled ? (m_option_flags | COMMENTS_ADD_LEADING_SPACE) : (m_option_flags & ~COMMENTS_ADD_LEADING_SPACE)); return *this; }
C4_ALWAYS_INLINE bool indent_flow_ml() const noexcept { return (m_option_flags & INDENT_FLOW_ML) != 0; }
EmitOptions& indent_flow_ml(bool enabled) noexcept { m_option_flags = (EmitOptionFlags_e)(enabled ? (m_option_flags | INDENT_FLOW_ML) : (m_option_flags & ~INDENT_FLOW_ML)); return *this; }
@@ -145,6 +160,8 @@ public:
, m_depth()
, m_ilevel()
, m_pws()
_RYML_WITH_COMMENTS(, m_wsonly())
_RYML_WITH_COMMENTS(, m_comm_state())
{}
/** Construct the emitter and its internal Writer state, using default emit options.
@@ -159,6 +176,8 @@ public:
, m_depth()
, m_ilevel()
, m_pws()
_RYML_WITH_COMMENTS(, m_wsonly())
_RYML_WITH_COMMENTS(, m_comm_state())
{}
public:
@@ -266,6 +285,20 @@ private:
void _writev_json(id_type id, NodeType ty);
void _write_scalar_json_dquo(csubstr s);
private: // comments
#ifdef RYML_WITH_COMMENTS
C4_ALWAYS_INLINE void _comm_push() { m_comm_state.push(CommState{}); }
C4_ALWAYS_INLINE void _comm_pop() { m_ilevel -= m_comm_state.pop().extra_indentation; }
CommentData const* _comm_get(id_type node, CommentType_e type, bool indent_extra=false);
CommentData const* _write_comm_trailing(id_type node, CommentType_e type, bool indent_extra=false);
CommentData const* _write_comm_leading(id_type node, CommentType_e type, bool indent_extra=false);
void _write_comm_trailing(CommentData const* comm);
void _write_comm_leading(CommentData const* comm);
void _write_comm(csubstr s, id_type indentation);
void _write_comm_leadspace(csubstr s, id_type indentation);
#endif
private:
void _write_tag(csubstr tag)
@@ -298,21 +331,25 @@ private:
{
this->Writer::_do_write(std::forward<const char (&)[N]>(a));
m_col += N-1;
_RYML_WITH_COMMENTS(m_wsonly = false;)
}
C4_ALWAYS_INLINE void _write(csubstr s)
{
this->Writer::_do_write(s);
m_col += s.len;
_RYML_WITH_COMMENTS(m_wsonly = false;)
}
C4_ALWAYS_INLINE void _write(char c)
{
this->Writer::_do_write(c);
++m_col;
_RYML_WITH_COMMENTS(m_wsonly = false;)
}
C4_ALWAYS_INLINE void _write(char c, size_t num)
{
this->Writer::_do_write(c, num);
m_col += num;
_RYML_WITH_COMMENTS(m_wsonly = false;)
}
/// write a newline and reset the column
@@ -320,6 +357,7 @@ private:
{
this->Writer::_do_write('\n');
m_col = 0;
_RYML_WITH_COMMENTS(m_wsonly = true;)
}
private: // pending whitespace
@@ -365,6 +403,19 @@ private:
id_type m_depth;
id_type m_ilevel;
Pws_e m_pws;
#ifdef RYML_WITH_COMMENTS
bool m_wsonly; ///< line contains only whitespace
struct CommState
{
CommentData const* latest;
CommentData const* comm;
id_type extra_indentation;
#ifdef RYML_USE_ASSERT
CommentType_e latest_query;
#endif
};
detail::stack<CommState> m_comm_state;
#endif
private:

View File

@@ -208,6 +208,10 @@ public:
_remove_speculative();
m_curr->node_id = m_tree->last_child(root);
m_curr->tr_data = m_tree->_p(m_curr->node_id);
#ifdef RYML_WITH_COMMENTS
m_tree->_p(m_curr->node_id)->m_first_comment = NONE;
m_tree->_p(m_curr->node_id)->m_last_comment = NONE;
#endif
}
}
else
@@ -582,6 +586,31 @@ public:
/** @} */
public:
/** @name comments */
/** @{ */
#ifdef RYML_WITH_COMMENTS
/** add comment
*
* @warning This is only available if RYML_WITH_COMMENTS is defined. */
void add_comment(csubstr txt, CommentType_e type)
{
NodeData * d = m_curr->tr_data;
_c4dbgpf("node[{}]: comment! type={} txt=[{}]~~~{}~~~", m_tree->id(d), type, txt.len, txt);
if(type == COMM_VAL_BRACKET_TRAILING || type == COMM_VAL_BRACKET_LEADING)
{
_RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent && m_parent->tr_data->m_type.is_flow());
d = m_parent->tr_data;
_c4dbgpf("node[{}]: comment to parent! [{}]~~~{}~~~", m_tree->id(d), txt.len, txt);
}
m_tree->set_comment(d, type, txt);
}
#endif // RYML_WITH_COMMENTS
/** @} */
public:
/** @name arena functions */
@@ -746,25 +775,32 @@ public:
void _remove_speculative()
{
_c4dbgp("remove speculative node");
_RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
_RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
if(m_tree->has_parent(last_added))
if(m_tree->_p(last_added)->m_type == NOTYPE)
m_tree->remove(last_added);
const id_type speculative = m_tree->size() - 1;
const NodeData* node = m_tree->_p(speculative);
_c4dbgpf("remove speculative node={}, parent={}", speculative, node->m_parent);
if(node->m_parent != NONE && node->m_type == NOTYPE)
{
_RYML_WITH_COMMENTS(_RYML_ASSERT_BASIC_(m_tree->callbacks(), node->m_first_comment == NONE));
_RYML_WITH_COMMENTS(_RYML_ASSERT_BASIC_(m_tree->callbacks(), node->m_last_comment == NONE));
m_tree->remove(speculative);
}
}
void _remove_speculative_with_parent()
{
_RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
_RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
const id_type last_added = m_tree->size() - 1;
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_parent(last_added), m_tree, last_added);
if(m_tree->_p(last_added)->m_type == NOTYPE)
const id_type speculative = m_tree->size() - 1;
const NodeData* node = m_tree->_p(speculative);
_c4dbgpf("remove speculative node={}, parent={}", speculative, node->m_parent);
_RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_parent(speculative), m_tree, speculative);
if(node->m_type == NOTYPE)
{
_c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
m_tree->remove(last_added);
_RYML_WITH_COMMENTS(_RYML_ASSERT_BASIC_(m_tree->callbacks(), node->m_first_comment == NONE));
_RYML_WITH_COMMENTS(_RYML_ASSERT_BASIC_(m_tree->callbacks(), node->m_last_comment == NONE));
m_tree->remove(speculative);
}
}

View File

@@ -388,6 +388,23 @@ public:
/** @} */
public:
#ifdef RYML_WITH_COMMENTS
/** @name comments */
/** @{ */
C4_ALWAYS_INLINE CommentData const* comment( comment_data_type type_flags=COMM_ANY) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, type_flags); }
C4_ALWAYS_INLINE CommentData const* comment(id_type comment_id, comment_data_type type_flags=COMM_ANY) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, comment_id, type_flags); }
C4_ALWAYS_INLINE CommentData const* comment(CommentData const* prev, comment_data_type type_flags=COMM_ANY) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, prev, type_flags); }
C4_ALWAYS_INLINE CommentData const* comment( CommentType_e type) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, (comment_data_type)type); }
C4_ALWAYS_INLINE CommentData const* comment(id_type comment_id, CommentType_e type) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, comment_id, (comment_data_type)type); }
C4_ALWAYS_INLINE CommentData const* comment(CommentData const* prev, CommentType_e type) const RYML_NOEXCEPT { _C4RR(); return tree_->comment(id_, prev, (comment_data_type)type); }
/** @} */
#endif
public:
/** @name square_brackets

View File

@@ -266,6 +266,7 @@ ParseEngine<EventHandler>::ParseEngine(EventHandler *evt_handler, ParserOptions
, m_evt_handler(evt_handler)
, m_pending_anchors()
, m_pending_tags()
_RYML_WITH_COMMENTS(, m_pending_comment())
, m_was_inside_qmrk(false)
, m_doc_empty(false)
, m_prev_colon(npos)
@@ -286,6 +287,7 @@ ParseEngine<EventHandler>::ParseEngine(ParseEngine &&that) noexcept
, m_evt_handler(that.m_evt_handler)
, m_pending_anchors(that.m_pending_anchors)
, m_pending_tags(that.m_pending_tags)
_RYML_WITH_COMMENTS(, m_pending_comment(that.m_pending_comment))
, m_was_inside_qmrk(false)
, m_doc_empty(false)
, m_prev_colon(npos)
@@ -306,6 +308,7 @@ ParseEngine<EventHandler>::ParseEngine(ParseEngine const& that)
, m_evt_handler(that.m_evt_handler)
, m_pending_anchors(that.m_pending_anchors)
, m_pending_tags(that.m_pending_tags)
_RYML_WITH_COMMENTS(, m_pending_comment(that.m_pending_comment))
, m_was_inside_qmrk(false)
, m_doc_empty(false)
, m_prev_colon(npos)
@@ -334,6 +337,7 @@ ParseEngine<EventHandler>& ParseEngine<EventHandler>::operator=(ParseEngine &&th
m_evt_handler = that.m_evt_handler;
m_pending_anchors = that.m_pending_anchors;
m_pending_tags = that.m_pending_tags;
_RYML_WITH_COMMENTS(m_pending_comment = that.m_pending_comment;)
m_was_inside_qmrk = that.m_was_inside_qmrk;
m_doc_empty = that.m_doc_empty;
m_prev_colon = that.m_prev_colon;
@@ -358,6 +362,7 @@ ParseEngine<EventHandler>& ParseEngine<EventHandler>::operator=(ParseEngine cons
m_evt_handler = that.m_evt_handler;
m_pending_anchors = that.m_pending_anchors;
m_pending_tags = that.m_pending_tags;
_RYML_WITH_COMMENTS(m_pending_comment = that.m_pending_comment;)
m_was_inside_qmrk = that.m_was_inside_qmrk;
m_doc_empty = that.m_doc_empty;
m_prev_colon = that.m_prev_colon;
@@ -382,6 +387,7 @@ void ParseEngine<EventHandler>::_clr()
m_evt_handler = {};
m_pending_anchors = {};
m_pending_tags = {};
_RYML_WITH_COMMENTS(m_pending_comment = {};)
m_was_inside_qmrk = false;
m_doc_empty = true;
m_prev_colon = npos;
@@ -413,6 +419,7 @@ void ParseEngine<EventHandler>::_reset()
{
m_pending_anchors = {};
m_pending_tags = {};
_RYML_WITH_COMMENTS(m_pending_comment = {};)
m_doc_empty = true;
m_was_inside_qmrk = false;
m_prev_colon = npos;
@@ -613,6 +620,10 @@ void ParseEngine<EventHandler>::_skipchars(const char (&chars)[N])
template<class EventHandler>
void ParseEngine<EventHandler>::_skip_comment()
{
#ifdef RYML_WITH_COMMENTS
if(m_options.with_comments())
return;
#endif
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.begins_with('#'));
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.is_sub(m_evt_handler->m_curr->line_contents.full));
csubstr rem = m_evt_handler->m_curr->line_contents.rem;
@@ -636,6 +647,10 @@ void ParseEngine<EventHandler>::_skip_comment()
template<class EventHandler>
void ParseEngine<EventHandler>::_maybe_skip_comment()
{
#ifdef RYML_WITH_COMMENTS
if(m_options.with_comments())
return;
#endif
csubstr s = m_evt_handler->m_curr->line_contents.rem.triml(' ');
if(s.begins_with('#'))
{
@@ -765,6 +780,70 @@ csubstr ParseEngine<EventHandler>::_scan_tag()
}
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
template<class EventHandler>
bool ParseEngine<EventHandler>::_maybe_advance_to_trailing_comment()
{
if(!m_options.with_comments())
return false;
_maybe_skip_whitespace_tokens();
csubstr rem = m_evt_handler->m_curr->line_contents.rem;
return (rem.len && rem.str[0] == '#');
}
template<class EventHandler>
substr ParseEngine<EventHandler>::_scan_comment_flow()
{
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_evt_handler->m_curr->line_contents.rem.begins_with('#'));
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_options.with_comments());
size_t beg = m_evt_handler->m_curr->pos.offset;
size_t end = beg + 1; // we know it begins with #
csubstr rem = m_evt_handler->m_curr->line_contents.rem;
do {
_line_progressed(rem.len);
end = m_evt_handler->m_curr->pos.offset;
if(!_finished_file())
{
_c4dbgp("next line!");
_line_ended();
_scan_line();
}
else
{
_c4dbgp("file finished!");
break;
}
// this is the next line
rem = m_evt_handler->m_curr->line_contents.rem;
// skip leading whitespace
size_t pos = 0;
char c = '\0';
for(; pos < rem.len; ++pos)
{
c = rem.str[pos];
if(c != ' ' _RYML_WITH_TAB_TOKENS(&& c != '\t'))
break;
}
// continue only if the next character is #
if(c != '#')
break;
} while(true);
substr result = m_buf.range(beg, end);
_c4dbgpf("scanned comment: [{}]~~~{}~~~", result.len, result);
return result;
}
template<class EventHandler>
substr ParseEngine<EventHandler>::_scan_comment_blck()
{
return _scan_comment_flow(); // FIXME
}
#endif
//-----------------------------------------------------------------------------
template<class EventHandler>
@@ -1540,17 +1619,47 @@ void ParseEngine<EventHandler>::_save_indentation()
template<class EventHandler>
void ParseEngine<EventHandler>::_end_map_flow()
{
#ifdef RYML_WITH_COMMENTS
if(m_pending_comment.type != COMM_NONE)
{
_c4dbgp("mapflow: end: add pending comment");
_handle_flow_end_comment();
}
#endif
bool multiline = m_options.detect_flow_ml() && m_evt_handler->m_parent->pos.line < m_evt_handler->m_curr->pos.line;
_c4dbgpf("mapflow: end, multiline={}", multiline);
m_evt_handler->end_map_flow(multiline);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment()) // } # trailing comment applies to the map
{
_c4dbgp("mapflow: trailing comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_TRAILING);
}
#endif
}
template<class EventHandler>
void ParseEngine<EventHandler>::_end_seq_flow()
{
#ifdef RYML_WITH_COMMENTS
if(m_pending_comment.type != COMM_NONE)
{
_c4dbgp("seqflow: end: add pending comment");
_handle_flow_end_comment();
}
#endif
bool multiline = m_options.detect_flow_ml() && m_evt_handler->m_parent->pos.line < m_evt_handler->m_curr->pos.line;
_c4dbgpf("seqflow: end, multiline={}", multiline);
m_evt_handler->end_seq_flow(multiline);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment()) // "] # trailing comment applies to the seq"
{
_c4dbgp("seqflow: trailing comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_TRAILING);
}
#endif
}
template<class EventHandler>
@@ -3510,6 +3619,78 @@ FilterResult ParseEngine<EventHandler>::filter_scalar_block_folded_in_place(subs
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
// a debugging scaffold:
#if 0
#define _c4dbgfc(fmt, ...) _c4dbgpf("filter_comm: " fmt, __VA_ARGS__)
#else
#define _c4dbgfc(...)
#endif
template<class EventHandler>
csubstr ParseEngine<EventHandler>::_filter_comment(substr comment)
{
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, comment.len >= 1);
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, comment.begins_with('#'));
size_t wpos = 1; // write position. no need to overwrite the first '#'
size_t rpos = 1; // read position. skip the first '#'
size_t last = 1; // read mark. position of last copied character
for(; rpos < comment.len; ++rpos)
{
_c4dbgfc("[{}/{}]='{}'", rpos, comment.len, _c4prc(comment.str[rpos]));
if(comment.str[rpos] != '\n')
continue;
// copy newlines if they are not at the end
size_t inclusive = rpos + 1 < comment.len ? rpos + 1 : rpos;
size_t num_move = inclusive - last;
if(num_move)
{
_c4dbgfc("... copy {}:{} <- {}:{} [{}]'{}' ", wpos, wpos + num_move, last, last + num_move, num_move, comment.sub(last, num_move));
if(wpos != last)
memmove(comment.str + wpos, comment.str + last, num_move);
wpos += num_move;
}
++rpos; // advance past the newline
// every comment line must begin with whitespace. skip it.
for(; rpos < comment.len; ++rpos)
{
if(comment.str[rpos] == ' ' _RYML_WITH_TAB_TOKENS(|| comment.str[rpos] != '\t'))
{
_c4dbgfc("... skip [{}/{}]='{}' ", rpos, comment.len, _c4prc(comment.str[rpos]));
}
else
{
break;
}
}
// now the current character must be # or we're at the end
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, rpos == comment.len || comment.str[rpos] == '#');
last = rpos + 1;
}
// copy remaining characters
if(last < comment.len)
{
size_t num_move = comment.len - last;
_c4dbgfc("final copy: {}:{} <- {}:{} [{}]'{}' ", wpos, wpos + num_move, last, last + num_move, num_move, comment.sub(last, num_move));
if(wpos != last)
memmove(comment.str + wpos, comment.str + last, num_move);
wpos += num_move;
}
csubstr result = comment.range(1, wpos);
_c4dbgpf("filtered comment: [{}]~~~{}~~~ ", result.len, result);
return result;
}
#undef _c4dbgfc
#endif // RYML_WITH_COMMENTS
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@@ -4077,8 +4258,7 @@ void ParseEngine<EventHandler>::_handle_flow_skip_whitespace()
_c4dbgpf("starts with whitespace: '{}'", _c4prc(m_evt_handler->m_curr->line_contents.rem.str[0]));
_skipchars(" \t");
}
// comments
if(m_evt_handler->m_curr->line_contents.rem.begins_with('#'))
if(_RYML_WITH_COMMENTS((!m_options.with_comments()) &&) m_evt_handler->m_curr->line_contents.rem.begins_with('#'))
{
_c4dbgpf("it's a comment: {}", m_evt_handler->m_curr->line_contents.rem);
_line_progressed(m_evt_handler->m_curr->line_contents.rem.len);
@@ -4433,6 +4613,77 @@ void ParseEngine<EventHandler>::_handle_bom(Encoding_e enc)
}
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
template<class EventHandler>
void ParseEngine<EventHandler>::_pend_comment(csubstr txt, CommentType_e type)
{
_c4dbgpf("pend comment! {}", (uint32_t)type);
_RYML_ASSERT_BASIC_(callbacks(), m_pending_comment.type == COMM_NONE);
_RYML_ASSERT_BASIC_(callbacks(), type != COMM_NONE);
m_pending_comment.txt = txt;
m_pending_comment.type = type;
}
template<class EventHandler>
void ParseEngine<EventHandler>::_maybe_apply_pending_comment()
{
if(m_pending_comment.type != COMM_NONE)
{
_c4dbgpf("apply pending comment! {}", (uint32_t)m_pending_comment.type);
m_evt_handler->add_comment(m_pending_comment.txt, m_pending_comment.type);
m_pending_comment.type = COMM_NONE;
}
}
template<class EventHandler>
void ParseEngine<EventHandler>::_apply_pending_comment(CommentType_e expect_type, CommentType_e actual_type)
{
_c4dbgpf("apply pending comment! {} -> {}", (uint32_t)expect_type, (uint32_t)actual_type);
_RYML_ASSERT_BASIC_(callbacks(), m_pending_comment.type == expect_type);
m_evt_handler->add_comment(m_pending_comment.txt, actual_type);
m_pending_comment.type = COMM_NONE;
}
template<class EventHandler>
void ParseEngine<EventHandler>::_maybe_apply_pending_comment(CommentType_e expect_type, CommentType_e actual_type)
{
if(m_pending_comment.type != COMM_NONE)
_apply_pending_comment(expect_type, actual_type);
}
template<class EventHandler>
void ParseEngine<EventHandler>::_handle_flow_end_comment()
{
if(m_pending_comment.type == COMM_LEADING)
_apply_pending_comment(COMM_LEADING, COMM_VAL_BRACKET_LEADING);
else if(m_pending_comment.type == COMM_VAL_TRAILING)
_apply_pending_comment(COMM_VAL_TRAILING, COMM_TRAILING);
else
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, false && "not implemented");
}
template<class EventHandler>
void ParseEngine<EventHandler>::_maybe_handle_leading_comment(CommentType_e current)
{
if(m_pending_comment.type != COMM_NONE)
{
bool leading_exists = (m_evt_handler->m_curr->leading_comments & COMM_LEADING);
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_pending_comment.type == COMM_LEADING);
CommentType_e actual = leading_exists ? current : COMM_LEADING;
_c4dbgpf("pending leading comment! context={} leading_exists={} actual={}", current, leading_exists, actual);
_apply_pending_comment(COMM_LEADING, actual);
m_evt_handler->m_curr->leading_comments |= actual;
}
else if(current & (COMM_VAL_LEADING2|COMM_VAL_ANCHOR_LEADING))
{
m_evt_handler->m_curr->leading_comments |= COMM_LEADING;
}
}
#endif // RYML_WITH_COMMENTS
//-----------------------------------------------------------------------------
template<class EventHandler>
@@ -4833,6 +5084,15 @@ seqimap_start:
m_evt_handler->set_val_ref(ref);
addrem_flags(RNXT, RVAL);
}
#ifdef RYML_WITH_COMMENTS
else if(first == '#')
{
_c4dbgp("seqimap[RVAL]: comment!");
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_options.with_comments());
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_COLON_TRAILING);
}
#endif
else
{
_c4err("parse error");
@@ -5016,60 +5276,107 @@ seqflow_start:
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, has_none(RNXT));
const char first = m_evt_handler->m_curr->line_contents.rem.str[0];
ScannedScalar sc;
// block scalars (ie | and >) cannot appear in flow containers,
// so we don't need to check for those characters.
if(first == '\'')
{
_c4dbgp("seqflow[RVAL]: scanning single-quoted scalar");
_c4dbgp("seqflow[RVAL]: squo scalar");
sc = _scan_scalar_squot();
csubstr maybe_filtered = _maybe_filter_val_scalar_squot(sc);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->set_val_scalar_squoted(maybe_filtered);
addrem_flags(RNXT, RVAL);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
_pend_comment(comm, COMM_VAL_TRAILING);
}
#endif
}
else if(first == '"')
{
_c4dbgp("seqflow[RVAL]: scanning double-quoted scalar");
_c4dbgp("seqflow[RVAL]: dquo scalar");
sc = _scan_scalar_dquot();
csubstr maybe_filtered = _maybe_filter_val_scalar_dquot(sc);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->set_val_scalar_dquoted(maybe_filtered);
addrem_flags(RNXT, RVAL);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
_pend_comment(comm, COMM_VAL_TRAILING);
}
#endif
}
// block scalars (ie | and >) cannot appear in flow containers
else if(_scan_scalar_plain_seq_flow(&sc))
{
_c4dbgp("seqflow[RVAL]: it's a scalar.");
_c4dbgp("seqflow[RVAL]: plain scalar.");
csubstr maybe_filtered = _maybe_filter_val_scalar_plain(sc, m_evt_handler->m_curr->indref);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->set_val_scalar_plain(maybe_filtered);
addrem_flags(RNXT, RVAL);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
_pend_comment(comm, COMM_VAL_TRAILING);
}
#endif
}
else if(first == '[')
{
_c4dbgp("seqflow[RVAL]: start child seqflow");
addrem_flags(RNXT, RVAL);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->begin_seq_val_flow();
_set_indentation(m_evt_handler->m_parent->indref);
addrem_flags(RVAL, RNXT);
_line_progressed(1);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_BRACKET_TRAILING);
}
#endif
}
else if(first == '{')
{
_c4dbgp("seqflow[RVAL]: start child mapflow");
addrem_flags(RNXT, RVAL);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->begin_map_val_flow();
_set_indentation(m_evt_handler->m_parent->indref);
addrem_flags(RMAP|RKEY, RSEQ|RVAL|RNXT);
_line_progressed(1);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_BRACKET_TRAILING);
}
#endif
goto seqflow_finish;
}
else if(first == ']') // this happens on a trailing comma like ", ]"
{
_c4dbgp("seqflow[RVAL]: end!");
_line_progressed(1);
_end_seq_flow();
_end_seq_flow(); // handles comments inside
goto seqflow_finish;
}
else if(first == '*')
{
csubstr ref = _scan_ref_seq();
_c4dbgpf("seqflow[RVAL]: ref! [{}]~~~{}~~~", ref.len, ref);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_LEADING2);)
m_evt_handler->set_val_ref(ref);
addrem_flags(RNXT, RVAL);
}
@@ -5077,6 +5384,7 @@ seqflow_start:
{
csubstr anchor = _scan_anchor();
_c4dbgpf("seqflow[RVAL]: anchor! [{}]~~~{}~~~", anchor.len, anchor);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_ANCHOR_LEADING);)
m_evt_handler->set_val_anchor(anchor);
if(_maybe_scan_following_comma())
{
@@ -5084,12 +5392,21 @@ seqflow_start:
m_evt_handler->set_val_scalar_plain_empty();
m_evt_handler->add_sibling();
}
#ifdef RYML_WITH_COMMENTS
else if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: anchor comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_ANCHOR_TRAILING);
}
#endif
}
else if(first == '!')
{
csubstr tag = _scan_tag();
_c4dbgpf("seqflow[RVAL]: tag! [{}]~~~{}~~~", tag.len, tag);
_check_tag(tag);
_RYML_WITH_COMMENTS(_maybe_handle_leading_comment(COMM_VAL_TAG_LEADING);)
m_evt_handler->set_val_tag(tag);
if(_maybe_scan_following_comma())
{
@@ -5097,6 +5414,14 @@ seqflow_start:
m_evt_handler->set_val_scalar_plain_empty();
m_evt_handler->add_sibling();
}
#ifdef RYML_WITH_COMMENTS
else if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: tag comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_TAG_TRAILING);
}
#endif
}
else if(first == ':')
{
@@ -5121,6 +5446,15 @@ seqflow_start:
_maybe_skip_whitespace_tokens();
goto seqflow_finish;
}
#ifdef RYML_WITH_COMMENTS
else if(first == '#')
{
_c4dbgp("seqflow[RVAL]: comment!");
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_options.with_comments());
csubstr comm = _filter_comment(_scan_comment_flow());
_pend_comment(comm, COMM_LEADING);
}
#endif
else
{
_c4err("parse error");
@@ -5134,15 +5468,30 @@ seqflow_start:
if(first == ',')
{
_c4dbgp("seqflow[RNXT]: expect next val");
#ifdef RYML_WITH_COMMENTS
if(m_pending_comment.type == COMM_LEADING)
_apply_pending_comment(COMM_LEADING, COMM_COMMA_LEADING);
m_evt_handler->m_curr->leading_comments = 0;
#endif
addrem_flags(RVAL, RNXT);
m_evt_handler->add_sibling();
_line_progressed(1);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RNXT]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
if(m_pending_comment.type == COMM_VAL_TRAILING)
_apply_pending_comment(COMM_VAL_TRAILING, COMM_VAL_TRAILING);
m_evt_handler->add_comment(comm, COMM_TRAILING);
}
#endif
m_evt_handler->add_sibling();
}
else if(first == ']')
{
_c4dbgp("seqflow[RNXT]: end!");
_end_seq_flow();
_line_progressed(1);
_line_progressed(1); // call before
_end_seq_flow(); // handles comments inside
goto seqflow_finish;
}
else if(first == ':')
@@ -5154,6 +5503,15 @@ seqflow_start:
addrem_flags(RSEQIMAP|RVAL, RNXT);
goto seqflow_finish;
}
#ifdef RYML_WITH_COMMENTS
else if(first == '#')
{
_c4dbgp("seqflow[RNXT]: comment!");
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, m_options.with_comments());
csubstr comm = _filter_comment(_scan_comment_flow());
_pend_comment(comm, COMM_LEADING);
}
#endif
else
{
_c4err("parse error");
@@ -7372,7 +7730,7 @@ void ParseEngine<EventHandler>::_handle_unk()
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, has_none(RNXT|RSEQ|RMAP));
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, has_all(RTOP));
_maybe_skip_comment();
_RYML_WITHOUT_COMMENTS(_maybe_skip_comment();)
csubstr rem = m_evt_handler->m_curr->line_contents.rem;
if(!rem.len)
return;
@@ -7474,6 +7832,14 @@ void ParseEngine<EventHandler>::_handle_unk()
_set_indentation(startindent);
}
_line_progressed(1);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_BRACKET_TRAILING);
}
#endif
}
else if(first == '{')
{
@@ -7501,6 +7867,14 @@ void ParseEngine<EventHandler>::_handle_unk()
_set_indentation(startindent);
}
_line_progressed(1);
#ifdef RYML_WITH_COMMENTS
if(_maybe_advance_to_trailing_comment())
{
_c4dbgp("seqflow[RVAL]: comment!");
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, COMM_VAL_BRACKET_TRAILING);
}
#endif
}
else if(first == '-' && _is_blck_token(rem))
{
@@ -7606,6 +7980,21 @@ void ParseEngine<EventHandler>::_handle_unk()
const size_t line = m_evt_handler->m_curr->pos.line;
_add_annotation(&m_pending_tags, tag, indentation, line);
}
#ifdef RYML_WITH_COMMENTS
else if(first == '#')
{
_c4dbgp("unk: comment!");
if(m_options.with_comments())
{
csubstr comm = _filter_comment(_scan_comment_flow());
m_evt_handler->add_comment(comm, m_doc_empty ? COMM_LEADING : COMM_FOOTER);
}
else
{
_skip_comment();
}
}
#endif
else
{
_RYML_ASSERT_BASIC_(m_evt_handler->m_stack.m_callbacks, ! has_any(SSCL));

View File

@@ -6,6 +6,13 @@
#endif
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_COMMENT_TYPE_HPP_
#include "c4/yml/comment_type.hpp"
#endif
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
@@ -494,6 +501,12 @@ private:
csubstr _scan_ref_map();
csubstr _scan_tag();
#ifdef RYML_WITH_COMMENTS
bool _maybe_advance_to_trailing_comment();
substr _scan_comment_flow();
substr _scan_comment_blck();
#endif
public: // exposed for testing
/** @cond dev */
@@ -514,6 +527,10 @@ public: // exposed for testing
csubstr _maybe_filter_val_scalar_literal(ScannedBlock const& sb);
csubstr _maybe_filter_key_scalar_folded(ScannedBlock const& sb);
csubstr _maybe_filter_val_scalar_folded(ScannedBlock const& sb);
#ifdef RYML_WITH_COMMENTS
csubstr _filter_comment(substr s);
#endif
/** @endcond */
private:
@@ -704,6 +721,15 @@ private:
void _check_tag(csubstr tag);
#ifdef RYML_WITH_COMMENTS
void _pend_comment(csubstr txt, CommentType_e type);
void _maybe_apply_pending_comment();
void _maybe_apply_pending_comment(CommentType_e expect_type, CommentType_e actual_type);
void _apply_pending_comment(CommentType_e expect_type, CommentType_e actual_type);
void _handle_flow_end_comment();
void _maybe_handle_leading_comment(CommentType_e current);
#endif
private:
ParserOptions m_options;
@@ -721,6 +747,14 @@ private:
Annotation m_pending_anchors;
Annotation m_pending_tags;
#ifdef RYML_WITH_COMMENTS
struct PendingComment
{
operator bool() const noexcept { return type != COMM_NONE; }
csubstr txt; CommentType_e type;
};
PendingComment m_pending_comment;
#endif
bool m_was_inside_qmrk;
bool m_doc_empty = true;

View File

@@ -5,6 +5,12 @@
#include "c4/yml/error.hpp"
#endif
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_COMMENT_TYPE_HPP_
#include "c4/yml/comment_type.hpp"
#endif
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
namespace c4 {
@@ -123,6 +129,7 @@ struct ParserState
size_t scalar_col; // the column where the scalar (or its quotes) begin
bool more_indented;
bool has_children;
_RYML_WITH_COMMENTS(comment_data_type leading_comments;)
ParserState() = default;
@@ -138,6 +145,7 @@ struct ParserState
scalar_col = 0;
indref = 0;
has_children = false;
_RYML_WITH_COMMENTS(leading_comments = 0;)
}
void reset_after_push()
@@ -147,6 +155,7 @@ struct ParserState
more_indented = false;
++level;
has_children = false;
_RYML_WITH_COMMENTS(leading_comments = 0;)
}
C4_ALWAYS_INLINE void reset_before_pop(ParserState const& to_pop)

View File

@@ -89,6 +89,11 @@ Tree::Tree(Callbacks const& cb)
, m_free_tail(NONE)
, m_arena()
, m_arena_pos(0)
#ifdef RYML_WITH_COMMENTS
, m_comments_buf()
, m_comments_cap()
, m_comments_size()
#endif // RYML_WITH_COMMENTS
, m_callbacks(cb)
, m_tag_directives()
{
@@ -101,6 +106,16 @@ Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
reserve_arena(arena_capacity);
}
#ifdef RYML_WITH_COMMENTS
Tree::Tree(id_type node_capacity, size_t arena_capacity, id_type comment_capacity, Callbacks const& cb)
: Tree(cb)
{
reserve(node_capacity);
reserve_arena(arena_capacity);
reserve_comments(comment_capacity);
}
#endif // RYML_WITH_COMMENTS
Tree::~Tree()
{
_free();
@@ -152,6 +167,14 @@ void Tree::_free()
_RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
}
_clear();
#ifdef RYML_WITH_COMMENTS
if(m_comments_buf)
{
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_cap > 0, this, NONE);
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_cap >= m_comments_size, this, NONE);
_RYML_CB_FREE(m_callbacks, m_comments_buf, CommentData, m_comments_cap);
}
#endif // RYML_WITH_COMMENTS
}
@@ -171,6 +194,11 @@ void Tree::_clear()
m_arena_pos = 0;
for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
m_tag_directives[i] = {};
#ifdef RYML_WITH_COMMENTS
m_comments_buf = nullptr;
m_comments_cap = 0;
m_comments_size = 0;
#endif // RYML_WITH_COMMENTS
}
void Tree::_copy(Tree const& that)
@@ -200,6 +228,16 @@ void Tree::_copy(Tree const& that)
}
for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
m_tag_directives[i] = that.m_tag_directives[i];
#ifdef RYML_WITH_COMMENTS
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_buf == nullptr, this, NONE);
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_cap == 0, this, NONE);
if(that.m_comments_size)
{
_RYML_ASSERT_VISIT_(m_callbacks, that.m_comments_cap >= that.m_comments_size, this, NONE);
m_comments_buf = _RYML_CB_ALLOC(m_callbacks, CommentData, that.m_comments_size);
memcpy(m_comments_buf, that.m_comments_buf, (size_t)that.m_comments_size * sizeof(CommentData));
}
#endif // RYML_WITH_COMMENTS
}
void Tree::_move(Tree & that) noexcept
@@ -217,6 +255,13 @@ void Tree::_move(Tree & that) noexcept
for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
m_tag_directives[i] = that.m_tag_directives[i];
that._clear();
#ifdef RYML_WITH_COMMENTS
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_buf == nullptr, this, NONE);
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_cap == 0, this, NONE);
m_comments_buf = that.m_comments_buf;
m_comments_cap = that.m_comments_cap;
m_comments_size = that.m_comments_size;
#endif // RYML_WITH_COMMENTS
}
void Tree::_relocate(substr next_arena)
@@ -249,6 +294,13 @@ void Tree::_relocate(substr next_arena)
if(in_arena(td.handle))
td.handle = _relocated(td.handle, next_arena);
}
#ifdef RYML_WITH_COMMENTS
for(CommentData *C4_RESTRICT c = m_comments_buf, *e = m_comments_buf + m_comments_cap; c != e; ++c)
{
if(in_arena(c->m_text))
c->m_text = _relocated(c->m_text, next_arena);
}
#endif // RYML_WITH_COMMENTS
}
@@ -1862,6 +1914,149 @@ Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
void Tree::reserve_comments(id_type comments_cap)
{
if(comments_cap > m_comments_cap)
{
CommentData *tmp;
tmp = _RYML_CB_ALLOC(m_callbacks, CommentData, comments_cap);
if(m_comments_buf)
{
_RYML_ASSERT_VISIT_(m_callbacks, m_comments_cap >= m_comments_size, this, NONE);
if(m_comments_cap)
{
memcpy(tmp, m_comments_buf, (size_t)m_comments_cap * sizeof(CommentData));
}
_RYML_CB_FREE(m_callbacks, m_comments_buf, CommentData, m_comments_cap);
}
m_comments_buf = tmp;
m_comments_cap = comments_cap;
}
}
id_type Tree::_claim_comment()
{
id_type id = m_comments_size;
if(m_comments_size == m_comments_cap)
{
id_type next_cap = m_comments_cap ? m_comments_cap * 2u : 64u;
reserve_comments(next_cap);
}
++m_comments_size;
return id;
}
CommentData const* Tree::comment(id_type node_id, id_type comment_id, comment_data_type type) const
{
(void)node_id;
_RYML_ASSERT_VISIT_(m_callbacks, node_id < m_cap, this, node_id);
_RYML_ASSERT_VISIT_(m_callbacks, comment_id == NONE || comment_id == 0 || comment_id < m_comments_size, this, node_id);
for(id_type cid = comment_id; cid != NONE; cid = m_comments_buf[cid].m_next)
{
_RYML_ASSERT_VISIT_(m_callbacks, cid < m_comments_size, this, node_id);
if(m_comments_buf[cid].m_type & type)
return &m_comments_buf[cid];
else if(m_comments_buf[cid].m_type > type)
break;
}
return nullptr;
}
CommentData const* Tree::comment(id_type node_id, CommentData const* prev, comment_data_type type_flags) const
{
_RYML_ASSERT_VISIT_(m_callbacks, node_id < m_cap, this, node_id);
id_type comment_id = prev ? prev->m_next : _p(node_id)->m_first_comment;
return comment(node_id, comment_id, type_flags);
}
CommentData const* Tree::comment(id_type node_id, comment_data_type type) const
{
_RYML_ASSERT_VISIT_(m_callbacks, node_id < m_cap, this, node_id);
return comment(node_id, _p(node_id)->m_first_comment, type);
}
void Tree::set_comment(NodeData *n, CommentType_e type, csubstr const& txt)
{
id_type comid = NONE;
id_type prev = n->m_last_comment;
// find the comment or find a place to insert it
for(id_type cid = n->m_first_comment; cid != NONE; cid = m_comments_buf[cid].m_next)
{
if(m_comments_buf[cid].m_type == type)
{
comid = cid; // found the comment
}
else if(m_comments_buf[cid].m_type > type)
{
prev = m_comments_buf[cid].m_prev; // insert after this
break;
}
}
if(comid == NONE)
{
comid = _insert_comment(n, prev);
}
m_comments_buf[comid].m_type = type;
m_comments_buf[comid].m_text = txt;
}
void Tree::set_comment(id_type id, CommentType_e type, csubstr const& txt)
{
set_comment(_p(id), type, txt);
}
id_type Tree::_insert_comment(NodeData *n, id_type prev_comment)
{
id_type comid = _claim_comment();
if(n->m_first_comment == NONE) // list is empty
{
_RYML_ASSERT_VISIT_(m_callbacks, n->m_first_comment == NONE, this, id(n));
_RYML_ASSERT_VISIT_(m_callbacks, n->m_last_comment == NONE, this, id(n));
m_comments_buf[comid].m_prev = NONE;
m_comments_buf[comid].m_next = NONE;
n->m_first_comment = comid;
n->m_last_comment = comid;
}
else if(prev_comment == NONE) // insert at the head
{
_RYML_ASSERT_VISIT_(m_callbacks, n->m_first_comment != NONE, this, id(n));
_RYML_ASSERT_VISIT_(m_callbacks, n->m_last_comment != NONE, this, id(n));
m_comments_buf[n->m_first_comment].m_prev = comid;
m_comments_buf[comid].m_prev = NONE;
m_comments_buf[comid].m_next = n->m_first_comment;
n->m_first_comment = comid;
}
else // insert after prev
{
_RYML_ASSERT_VISIT_(m_callbacks, n->m_first_comment != NONE, this, id(n));
_RYML_ASSERT_VISIT_(m_callbacks, n->m_last_comment != NONE, this, id(n));
if(prev_comment != n->m_last_comment) // prev is in the middle
{
id_type next_comment = m_comments_buf[prev_comment].m_next;
m_comments_buf[comid].m_prev = prev_comment;
m_comments_buf[comid].m_next = next_comment;
m_comments_buf[prev_comment].m_next = comid;
m_comments_buf[next_comment].m_prev = comid;
}
else // prev is at the tail
{
m_comments_buf[n->m_last_comment].m_next = comid;
m_comments_buf[comid].m_prev = n->m_last_comment;
m_comments_buf[comid].m_next = NONE;
n->m_last_comment = comid;
}
}
return comid;
}
#endif // RYML_WITH_COMMENTS
} // namespace yml
} // namespace c4

View File

@@ -28,6 +28,12 @@
#include <c4/charconv.hpp>
#endif
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_COMMENT_TYPE_HPP_
#include "c4/yml/comment_type.hpp"
#endif
#endif
#include <cmath>
#include <limits>
@@ -196,10 +202,31 @@ struct NodeData
id_type m_last_child;
id_type m_next_sibling;
id_type m_prev_sibling;
#ifdef RYML_WITH_COMMENTS
id_type m_first_comment;
id_type m_last_comment;
#endif // RYML_WITH_COMMENTS
};
C4_MUST_BE_TRIVIAL_COPY(NodeData);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
struct CommentData
{
CommentType_e m_type;
csubstr m_text;
id_type m_prev;
id_type m_next;
};
C4_MUST_BE_TRIVIAL_COPY(CommentData);
#endif // RYML_WITH_COMMENTS
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@@ -216,6 +243,10 @@ public:
Tree(id_type node_capacity, size_t arena_capacity=0) : Tree(node_capacity, arena_capacity, get_callbacks()) {}
Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb);
#ifdef RYML_WITH_COMMENTS
Tree(id_type node_capacity, size_t arena_capacity, id_type comment_capacity, Callbacks const& cb);
#endif
~Tree();
Tree(Tree const& that);
@@ -1101,6 +1132,41 @@ private:
void _relocate(substr next_arena);
public:
#ifdef RYML_WITH_COMMENTS
/** @name comments [experimental]
*
* For an explanation of the comment types, see @ref
* CommentType_e. Comments are enabled only if @ref
* RYML_WITH_COMMENTS is defined. */
/** @{ */
void reserve_comments(id_type comment_capacity);
CommentData const* comment(id_type node_id, comment_data_type type_flags=COMM_ANY) const;
CommentData const* comment(id_type node_id, id_type comment_id, comment_data_type type_flags=COMM_ANY) const;
CommentData const* comment(id_type node_id, CommentData const* prev, comment_data_type type_flags=COMM_ANY) const;
C4_ALWAYS_INLINE CommentData const* comment(id_type node_id, CommentType_e type) const { return comment(node_id, (comment_data_type)type); }
C4_ALWAYS_INLINE CommentData const* comment(id_type node_id, id_type comment_id, CommentType_e type) const { return comment(node_id, comment_id, (comment_data_type)type); }
C4_ALWAYS_INLINE CommentData const* comment(id_type node_id, CommentData const* prev, CommentType_e type) const { return comment(node_id, prev, (comment_data_type)type); }
void set_comment(id_type node_id, CommentType_e type, csubstr const& txt);
void set_comment(NodeData *n, CommentType_e type, csubstr const& txt);
void rem_comments(id_type node_id); ///< remove all comments from the node
void rem_comment(id_type node_id, CommentType_e type);
private:
id_type _claim_comment();
id_type _insert_comment(NodeData *n, id_type prev_comment);
/** @} */
#endif // RYML_WITH_COMMENTS
public:
/** @cond dev*/
@@ -1256,6 +1322,11 @@ public:
dst.m_type = src.m_type;
dst.m_key = src.m_key;
dst.m_val = src.m_val;
#ifdef RYML_WITH_COMMENTS
// FIXME
dst.m_first_comment = src.m_first_comment;
dst.m_last_comment = src.m_last_comment;
#endif
}
void _copy_props(id_type dst_, Tree const* that_tree, id_type src_, type_bits src_mask)
@@ -1265,6 +1336,11 @@ public:
dst.m_type = (src.m_type & src_mask) | (dst.m_type & ~src_mask);
dst.m_key = src.m_key;
dst.m_val = src.m_val;
#ifdef RYML_WITH_COMMENTS
// FIXME
dst.m_first_comment = src.m_first_comment;
dst.m_last_comment = src.m_last_comment;
#endif
}
void _copy_props_wo_key(id_type dst_, Tree const* that_tree, id_type src_)
@@ -1273,6 +1349,11 @@ public:
auto const& C4_RESTRICT src = *that_tree->_p(src_);
dst.m_type = (src.m_type & ~_KEYMASK) | (dst.m_type & _KEYMASK);
dst.m_val = src.m_val;
#ifdef RYML_WITH_COMMENTS
// FIXME
dst.m_first_comment = src.m_first_comment;
dst.m_last_comment = src.m_last_comment;
#endif
}
void _copy_props_wo_key(id_type dst_, Tree const* that_tree, id_type src_, type_bits src_mask)
@@ -1281,6 +1362,11 @@ public:
auto const& C4_RESTRICT src = *that_tree->_p(src_);
dst.m_type = (src.m_type & ((~_KEYMASK)|src_mask)) | (dst.m_type & (_KEYMASK|~src_mask));
dst.m_val = src.m_val;
#ifdef RYML_WITH_COMMENTS
// FIXME
dst.m_first_comment = src.m_first_comment;
dst.m_last_comment = src.m_last_comment;
#endif
}
void _clear_type(id_type node)
@@ -1297,6 +1383,10 @@ public:
n->m_parent = NONE;
n->m_first_child = NONE;
n->m_last_child = NONE;
#ifdef RYML_WITH_COMMENTS
n->m_first_comment = NONE;
n->m_last_comment = NONE;
#endif // RYML_WITH_COMMENTS
}
void _clear_key(id_type node)
@@ -1342,6 +1432,12 @@ public:
substr m_arena;
size_t m_arena_pos;
#ifdef RYML_WITH_COMMENTS
CommentData *m_comments_buf;
id_type m_comments_cap;
id_type m_comments_size;
#endif // RYML_WITH_COMMENTS
Callbacks m_callbacks;
TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES];

View File

@@ -46,6 +46,9 @@ int32_t estimate_events_ints_size(csubstr src)
case '>':
case '?':
case '\n':
#ifdef RYML_WITH_COMMENTS
case '#':
#endif
count += 3;
break;
case '[':
@@ -90,6 +93,9 @@ static_assert((MASK & TAGV) == TAGV, "overflow?");
static_assert((MASK & AREN) == AREN, "overflow?");
static_assert((MASK & PSTR) == PSTR, "overflow?");
static_assert((MASK & UNFILT) == UNFILT, "overflow?");
#ifdef RYML_WITH_COMMENTS
static_assert((MASK & COMM) == COMM, "overflow?");
#endif
static_assert((MASK & LAST) == LAST, "overflow?");
static_assert((MASK & MASK) == MASK, "overflow?");
static_assert((MASK & WSTR) == WSTR, "overflow?");

View File

@@ -22,6 +22,11 @@
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#include <c4/yml/detail/dbgprint.hpp>
#endif
#ifdef RYML_WITH_COMMENTS
#ifndef _C4_YML_COMMENT_TYPE_HPP_
#include <c4/yml/comment_type.hpp>
#endif
#endif
#endif
// NOLINTBEGIN(hicpp-signed-bitwise)
@@ -43,6 +48,11 @@ using DataType = int32_t;
/** enumeration of integer event bits. */
typedef enum : DataType {
/// @cond dev
_COMM_START = 4, // internal
_COMM_MASKOUT = ((1 << _COMM_START) << 1) - 1u, // internal
/// @endcond
// Structure flags
KEY_ = (1 << 0), ///< as key
VAL_ = (1 << 1), ///< as value
@@ -61,6 +71,10 @@ typedef enum : DataType {
/// source and needs to be placed in the arena.
AREN = (1 << 3),
/// comment (requires RYML_WITH_COMMENTS, unused otherwise).
/// Needs to be higher bit than KEY_, VAL_, PSTR and AREN
COMM = (1 << _COMM_START),
// Event scopes
BEG_ = (1 << 5), ///< scope: begin
END_ = (1 << 6), ///< scope: end
@@ -112,10 +126,25 @@ typedef enum : DataType {
/// 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,
WSTR = SCLR|ALIA|ANCH|TAG_|TAGD|TAGV|YAML _RYML_WITH_COMMENTS(|COMM),
} EventFlags;
#ifdef RYML_WITH_COMMENTS
inline DataType encode_comment(ievt::DataType curr, CommentType_e comm)
{
curr &= (ievt::KEY_|ievt::VAL_); // keep only these
ievt::DataType encoded = ievt::DataType(static_cast<uint32_t>(comm) << static_cast<uint32_t>(ievt::_COMM_START + 1));
curr |= ievt::COMM|encoded;
return curr;
}
inline CommentType_e decode_comment(ievt::DataType curr)
{
curr &= ~(ievt::KEY_|ievt::VAL_|ievt::COMM);
return static_cast<CommentType_e>(static_cast<CommentType_e>(curr >> (ievt::_COMM_START + 1u)) & COMM_ANY);
}
#endif
} // namespace ievt
/** @} */
@@ -1196,6 +1225,25 @@ public:
/** @} */
public:
#ifdef RYML_WITH_COMMENTS
/** @name comments */
/** @{ */
/** add comment
*
* @warning This is only available if RYML_WITH_COMMENTS is defined. */
void add_comment(csubstr txt, CommentType_e type)
{
_c4dbgpf("node[{}]: comment! [{}]~~~{}~~~", txt.len, txt);
ievt::DataType prev = ((m_evt_prev < m_evt_size) ? m_evt[m_evt_prev] : 0);
_send_str_(txt, ievt::encode_comment(prev, type));
}
/** @} */
#endif
public:
/** @name YAML arena events */

View File

@@ -595,6 +595,29 @@ public:
/** @} */
public:
#ifdef RYML_WITH_COMMENTS
/** @name comments */
/** @{ */
/** add comment
*
* @warning This is only available if RYML_WITH_COMMENTS is defined. */
void add_comment(csubstr txt, CommentType_e type)
{
_c4dbgpf("comment! [{}]~~~{}~~~", txt.len, txt);
if(false) ;
#define _c4comm(sym, bit) else if(type & COMM_##sym) _send_("=COMM #[" #sym "]");
_RYML_DEFINE_COMMENTS(_c4comm)
#undef _c4comm
append_scalar_escaped(&_buf_(), txt);
_send_('\n');
}
/** @} */
#endif
public:
/** @name YAML arena events */

View File

@@ -118,6 +118,18 @@ size_t events_ints_to_testsuite(csubstr parsed_yaml,
for(ievt::DataType i = 0; i < evts_ints_sz; )
{
ievt::DataType evt = evts_ints[i];
#ifdef RYML_WITH_COMMENTS
if(evt & ievt::COMM)
{
CommentType_e comm = ievt::decode_comment(evt);
if(false) ;
#define _c4comm(sym, bit) else if(comm & COMM_##sym) append("=COMM #[" #sym "]");
_RYML_DEFINE_COMMENTS(_c4comm)
#undef _c4comm
append_esc(getstr(i));
}
else
#endif
if(evt & ievt::SCLR)
{
csubstr s = getstr(i);

View File

@@ -63,16 +63,57 @@ c4::EnumSymbols<yml::extra::ievt::EventFlags> esyms<yml::extra::ievt::EventFlags
{yml::extra::ievt::YAML, "YAML"},
{yml::extra::ievt::TAGD, "TAGD"},
{yml::extra::ievt::TAGV, "TAGV"},
#ifdef RYML_WITH_COMMENTS
{yml::extra::ievt::COMM, "COMM"},
#endif
};
return EnumSymbols<yml::extra::ievt::EventFlags>(syms);
}
#ifdef RYML_WITH_COMMENTS
template<>
c4::EnumSymbols<yml::CommentType_e> esyms<yml::CommentType_e>()
{
static constexpr const EnumSymbols<yml::CommentType_e>::Sym syms[] = {
#define _c4comm(sym, bit) {yml::COMM_##sym, #sym},
_RYML_DEFINE_COMMENTS(_c4comm)
#undef _c4comm
};
return EnumSymbols<yml::CommentType_e>(syms);
}
#endif
namespace yml {
namespace extra {
namespace ievt {
size_t to_chars(substr buf, ievt::DataType flags)
{
#ifndef RYML_WITH_COMMENTS
flags &= ievt::MASK; // clear any other bits
return c4::bm2str<ievt::EventFlags>(flags, buf.str, buf.len);
#else
if(!(flags & ievt::COMM))
{
flags &= ievt::MASK; // clear any other bits
return c4::bm2str<ievt::EventFlags>(flags, buf.str, buf.len);
}
else
{
ievt::DataType common = ievt::KEY_|ievt::VAL_|ievt::COMM;
size_t len = c4::bm2str<ievt::EventFlags>(flags & common, buf.str, buf.len);
substr rem = {};
if(len)
{
if(len < buf.len)
{
buf[len] = '|';
rem = buf.sub(len);
}
++len;
}
CommentType_e comment = ievt::decode_comment(flags);
len += c4::bm2str<yml::CommentType_e>(comment, rem.str, rem.len);
return len;
}
#endif
}
csubstr to_chars_sub(substr buf, ievt::DataType flags)
{

View File

@@ -91,6 +91,13 @@ ryml_add_test(engine_5_tag)
ryml_add_test(engine_6_qmrk)
ryml_add_test(engine_7_seqimap)
ryml_add_test(engine_8_scalars_tokens)
if(RYML_WITH_COMMENTS)
ryml_add_test(engine_9_comments_1_doc)
ryml_add_test(engine_9_comments_2_flow_seq)
ryml_add_test(engine_9_comments_3_flow_map)
ryml_add_test(engine_9_comments_4_blck_seq)
ryml_add_test(engine_9_comments_5_blck_map)
endif()
ryml_add_test(extra_testsuite)
ryml_add_test(extra_ints)
ryml_add_test(version)
@@ -139,6 +146,10 @@ ryml_add_test_case_group(anchor)
ryml_add_test_case_group(indentation)
ryml_add_test_case_group(number)
ryml_add_test_case_group(github_issues)
if(RYML_WITH_COMMENTS)
ryml_add_test_case_group(comments)
endif()
# workaround for a false positive warning in gcc14 --std=c++20 -O2
if(CMAKE_COMPILER_IS_GNUCXX
AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13)

211
test/test_comments.cpp Normal file
View File

@@ -0,0 +1,211 @@
#ifndef RYML_SINGLE_HEADER
#include <c4/yml/std/std.hpp>
#include <c4/yml/yml.hpp>
#endif
#include "./test_lib/test_group.hpp"
#include "./test_lib/test_group.def.hpp"
namespace c4 {
namespace yml {
struct CommentCase
{
csubstr input, expected;
int line;
};
struct Filter : public ::testing::TestWithParam<CommentCase>
{
};
static void test_filter(CommentCase const& cc)
{
ASSERT_LE(cc.expected.len, cc.input.len);
std::string buf_(cc.input.str, cc.input.len);
c4::substr buf = to_substr(buf_);
Parser::handler_type event_handler = {};
Parser parser(&event_handler);
csubstr actual = parser._filter_comment(buf);
ASSERT_TRUE(actual.is_sub(buf));
if(actual != cc.expected)
{
RYML_TRACE_FMT("see:\n{}:{}: case:\ninp=[{}]~~~{}~~~\nexp=[{}]~~~{}~~~\nact=[{}]~~~{}~~~",
__FILE__, cc.line,
cc.input.len, cc.input,
cc.expected.len, cc.expected,
actual.len, actual);
std::string expected_str(cc.expected.str, cc.expected.len);
std::string actual_str(actual.str, actual.len);
EXPECT_EQ(expected_str, actual_str);
}
}
TEST_P(Filter, test)
{
test_filter(GetParam());
}
static CommentCase test_cases_filter[] = {
#define commcase(input, output) CommentCase{csubstr(input), csubstr(output), __LINE__}
commcase("#", ""),
commcase("#\n", ""),
commcase("#\n#", "\n"),
commcase("#\n#\n", "\n"),
commcase("#\n#\n#", "\n\n"),
commcase("#\n#\n#\n", "\n\n"),
commcase("#", ""),
commcase("#\n", ""),
commcase("#\n #", "\n"),
commcase("#\n #\n", "\n"),
commcase("#\n #\n #", "\n\n"),
commcase("#\n #\n #\n", "\n\n"),
commcase("#", ""),
commcase("#\n", ""),
commcase("#\n #", "\n"),
commcase("#\n #\n", "\n"),
commcase("#\n #\n #", "\n\n"),
commcase("#\n #\n #\n", "\n\n"),
commcase("#a", "a"),
commcase("#a\n", "a"),
commcase("#a\n#b", "a\nb"),
commcase("#a\n#b\n", "a\nb"),
commcase("#a\n#b\n#", "a\nb\n"),
commcase("#a\n#b\n#c", "a\nb\nc"),
commcase("#a\n#b\n#c\n", "a\nb\nc"),
commcase("#a\n#b\n#c\n#", "a\nb\nc\n"),
commcase("#a\n#b\n#c\n#\n", "a\nb\nc\n"),
commcase("#a", "a"),
commcase("#a\n", "a"),
commcase("#a\n #b", "a\nb"),
commcase("#a\n #b\n", "a\nb"),
commcase("#a\n #b\n #", "a\nb\n"),
commcase("#a\n #b\n #c", "a\nb\nc"),
commcase("#a\n #b\n #c\n", "a\nb\nc"),
commcase("#a\n #b\n #c\n#", "a\nb\nc\n"),
commcase("#a\n #b\n #c\n#\n", "a\nb\nc\n"),
commcase("#a\n #b", "a\nb"),
commcase("#a\n #b\n", "a\nb"),
commcase("#a\n #b\n #", "a\nb\n"),
commcase("#a\n #b\n #c", "a\nb\nc"),
commcase("#a\n #b\n #c\n", "a\nb\nc"),
commcase("#a\n #b\n #c\n#", "a\nb\nc\n"),
commcase("#a\n #b\n #c\n#\n", "a\nb\nc\n"),
commcase("#aaaa", "aaaa"),
commcase("#aaaa\n", "aaaa"),
commcase("#aaaa\n#", "aaaa\n"),
commcase("#aaaa\n #bbbb", "aaaa\nbbbb"),
commcase("#aaaa\n #bbbb\n", "aaaa\nbbbb"),
commcase("#aaaa\n #bbbb\n #", "aaaa\nbbbb\n"),
commcase("#aaaa\n #bbbb\n #cccc", "aaaa\nbbbb\ncccc"),
commcase("#aaaa\n #bbbb\n #cccc\n", "aaaa\nbbbb\ncccc"),
commcase("#aaaa\n #bbbb\n #cccc\n #", "aaaa\nbbbb\ncccc\n"),
commcase("#aaaa\n #bbbb\n #cccc\n #\n", "aaaa\nbbbb\ncccc\n"),
commcase("#aaaa\n #bbbb", "aaaa\nbbbb"),
commcase("#aaaa\n #bbbb\n", "aaaa\nbbbb"),
commcase("#aaaa\n #bbbb\n #", "aaaa\nbbbb\n"),
commcase("#aaaa\n #bbbb\n #cccc", "aaaa\nbbbb\ncccc"),
commcase("#aaaa\n #bbbb\n #cccc\n", "aaaa\nbbbb\ncccc"),
commcase("#aaaa\n #bbbb\n #cccc\n #", "aaaa\nbbbb\ncccc\n"),
commcase("#aaaa\n #bbbb\n #cccc\n #\n", "aaaa\nbbbb\ncccc\n"),
commcase("#aa#aa#", "aa#aa#"),
commcase("#aa#aa#\n", "aa#aa#"),
commcase("#aa#aa#\n#", "aa#aa#\n"),
commcase("#aa#aa#\n #bb#bb#", "aa#aa#\nbb#bb#"),
commcase("#aa#aa#\n #bb#bb#\n", "aa#aa#\nbb#bb#"),
commcase("#aa#aa#\n #bb#bb#\n #", "aa#aa#\nbb#bb#\n"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#", "aa#aa#\nbb#bb#\ncc#cc#"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n", "aa#aa#\nbb#bb#\ncc#cc#"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n #", "aa#aa#\nbb#bb#\ncc#cc#\n"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n #\n", "aa#aa#\nbb#bb#\ncc#cc#\n"),
commcase("#aa#aa#\n #bb#bb#", "aa#aa#\nbb#bb#"),
commcase("#aa#aa#\n #bb#bb#\n", "aa#aa#\nbb#bb#"),
commcase("#aa#aa#\n #bb#bb#\n #", "aa#aa#\nbb#bb#\n"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#", "aa#aa#\nbb#bb#\ncc#cc#"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n", "aa#aa#\nbb#bb#\ncc#cc#"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n #", "aa#aa#\nbb#bb#\ncc#cc#\n"),
commcase("#aa#aa#\n #bb#bb#\n #cc#cc#\n #\n", "aa#aa#\nbb#bb#\ncc#cc#\n"),
// we don't skip leading whitespace
commcase("# aa#aa#", " aa#aa#"),
commcase("# aa#aa#\n", " aa#aa#"),
commcase("# aa#aa#\n#", " aa#aa#\n"),
commcase("# aa#aa#\n# ", " aa#aa#\n "),
commcase("# aa#aa#\n # bb#bb#", " aa#aa#\n bb#bb#"),
commcase("# aa#aa#\n # bb#bb#\n", " aa#aa#\n bb#bb#"),
commcase("# aa#aa#\n # bb#bb#\n #", " aa#aa#\n bb#bb#\n"),
commcase("# aa#aa#\n # bb#bb#\n # ", " aa#aa#\n bb#bb#\n "),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#", " aa#aa#\n bb#bb#\n cc#cc#"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n", " aa#aa#\n bb#bb#\n cc#cc#"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n #", " aa#aa#\n bb#bb#\n cc#cc#\n"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n #\n", " aa#aa#\n bb#bb#\n cc#cc#\n"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n # ", " aa#aa#\n bb#bb#\n cc#cc#\n "),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n # \n", " aa#aa#\n bb#bb#\n cc#cc#\n "),
commcase("# aa#aa#\n # bb#bb#", " aa#aa#\n bb#bb#"),
commcase("# aa#aa#\n # bb#bb#\n", " aa#aa#\n bb#bb#"),
commcase("# aa#aa#\n # bb#bb#\n #", " aa#aa#\n bb#bb#\n"),
commcase("# aa#aa#\n # bb#bb#\n #\n", " aa#aa#\n bb#bb#\n"),
commcase("# aa#aa#\n # bb#bb#\n # ", " aa#aa#\n bb#bb#\n "),
commcase("# aa#aa#\n # bb#bb#\n # \n", " aa#aa#\n bb#bb#\n "),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#", " aa#aa#\n bb#bb#\n cc#cc#"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n", " aa#aa#\n bb#bb#\n cc#cc#"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n #", " aa#aa#\n bb#bb#\n cc#cc#\n"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n #\n", " aa#aa#\n bb#bb#\n cc#cc#\n"),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n # ", " aa#aa#\n bb#bb#\n cc#cc#\n "),
commcase("# aa#aa#\n # bb#bb#\n # cc#cc#\n # \n", " aa#aa#\n bb#bb#\n cc#cc#\n "),
// we don't skip trailing whitespace
commcase("#aa#aa# ", "aa#aa# "),
commcase("#aa#aa# \n", "aa#aa# "),
commcase("#aa#aa# \n#", "aa#aa# \n"),
commcase("#aa#aa# \n# ", "aa#aa# \n "),
commcase("#aa#aa# \n #bb#bb# ", "aa#aa# \nbb#bb# "),
commcase("#aa#aa# \n #bb#bb# \n", "aa#aa# \nbb#bb# "),
commcase("#aa#aa# \n #bb#bb# \n #", "aa#aa# \nbb#bb# \n"),
commcase("#aa#aa# \n #bb#bb# \n # ", "aa#aa# \nbb#bb# \n "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# ", "aa#aa# \nbb#bb# \ncc#cc# "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n", "aa#aa# \nbb#bb# \ncc#cc# "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n #", "aa#aa# \nbb#bb# \ncc#cc# \n"),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n #\n", "aa#aa# \nbb#bb# \ncc#cc# \n"),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n # ", "aa#aa# \nbb#bb# \ncc#cc# \n "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n # \n", "aa#aa# \nbb#bb# \ncc#cc# \n "),
commcase("#aa#aa# \n #bb#bb# ", "aa#aa# \nbb#bb# "),
commcase("#aa#aa# \n #bb#bb# \n", "aa#aa# \nbb#bb# "),
commcase("#aa#aa# \n #bb#bb# \n #", "aa#aa# \nbb#bb# \n"),
commcase("#aa#aa# \n #bb#bb# \n # ", "aa#aa# \nbb#bb# \n "),
commcase("#aa#aa# \n #bb#bb# \n # \n", "aa#aa# \nbb#bb# \n "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# ", "aa#aa# \nbb#bb# \ncc#cc# "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n", "aa#aa# \nbb#bb# \ncc#cc# "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n #", "aa#aa# \nbb#bb# \ncc#cc# \n"),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n #\n", "aa#aa# \nbb#bb# \ncc#cc# \n"),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n # ", "aa#aa# \nbb#bb# \ncc#cc# \n "),
commcase("#aa#aa# \n #bb#bb# \n #cc#cc# \n # \n", "aa#aa# \nbb#bb# \ncc#cc# \n "),
#undef commcase
};
INSTANTIATE_TEST_SUITE_P(Comments,
Filter,
testing::ValuesIn(test_cases_filter),
[](const testing::TestParamInfo<CommentCase>& nfo) {
return c4::catrs<std::string>("line", nfo.param.line);
});
//-----------------------------------------------------------------------------
/*WIP*/GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(YmlTestCase);
// The other test executables are written to contain the declarative-style
// YmlTestCases. This executable does not have any but the build setup
// assumes it does, and links with the test lib, which requires an existing
// get_case() function. So this is here to act as placeholder until (if?)
// proper test cases are added here. This was detected in #47 (thanks
// @cburgard).
Case const* get_case(csubstr)
{
return nullptr;
}
} // namespace yml
} // namespace c4

View File

@@ -0,0 +1,952 @@
#include "./test_lib/test_engine.hpp"
// WARNING: don't use raw string literals -- g++-4.8 cannot accept
// them as macro arguments
#ifndef RYML_WITH_COMMENTS
#error this test requires RYML_WITH_COMMENTS to be defined
#endif
namespace c4 {
namespace yml {
constexpr const bool multiline = true;
constexpr const bool singleline = false;
COMMENT_TEST(DocEmptyMinimal,
"# 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
COMMENT_TEST(DocValMinimal,
"# 1" "\n"
"foo # 2" "\n"
"# 3" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 2" "\n"
"=COMM #[FOOTER] 3" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 2", COMM_TRAILING));
___(ps.add_comment(" 3", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(DocSeqMinimal,
"# 1" "\n"
"[ # 2" "\n"
"] # 3" "\n"
"# 4" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 3" "\n"
"=COMM #[FOOTER] 4" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 3", COMM_TRAILING));
___(ps.add_comment(" 4", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(DocMapMinimal,
"# 1" "\n"
"{ # 2" "\n"
"} # 3" "\n"
"# 4" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2" "\n"
"-MAP" "\n"
"=COMM #[TRAILING] 3" "\n"
"=COMM #[FOOTER] 4" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 3", COMM_TRAILING));
___(ps.add_comment(" 4", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
COMMENT_TEST(StreamMinimalBase,
"--- # 2" "\n"
"# 3" "\n"
"foo # 4" "\n"
"# 5" "\n"
,
"+STR" "\n"
"+DOC ---" "\n"
"=COMM #[DOC_TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[FOOTER] 5" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.add_comment(" 2", COMM_DOC_TRAILING));
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamMinimal,
"# 1" "\n"
"--- # 2" "\n"
"# 3" "\n"
"foo # 4" "\n"
"# 5" "\n"
"... # 6" "\n"
"# 7" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC ---" "\n"
"=COMM #[DOC_TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[FOOTER] 5" "\n"
"-DOC ..." "\n"
"=COMM #[TRAILING] 6" "\n"
"=COMM #[FOOTER] 7" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc_expl());
___(ps.add_comment(" 2", COMM_DOC_TRAILING));
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_FOOTER));
___(ps.end_doc_expl());
___(ps.add_comment(" 6", COMM_TRAILING));
___(ps.add_comment(" 7", COMM_FOOTER));
___(ps.end_stream());
}
COMMENT_TEST(DocValEmptyLeading,
"# 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValEmptyLeading,
"---" "\n"
"# 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValNoComment,
"---" "\n"
"foo" "\n"
,//-----------------------------------------------
"--- foo" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValTrailing,
"---" "\n"
"foo # 1" "\n"
,//-----------------------------------------------
"--- foo # 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 1" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValFooter,
"---" "\n"
"foo" "\n"
"# 1" "\n"
,//-----------------------------------------------
"--- foo" "\n"
"# 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"=COMM #[FOOTER] 1" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(DocValNoComment,
"foo" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC" "\n"
"=VAL :foo" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.set_val_scalar_plain("foo"));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(DocValTrailing,
"foo # 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 1" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(DocValFooter,
"foo" "\n"
"# 1" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC" "\n"
"=VAL :foo" "\n"
"=COMM #[FOOTER] 1" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValEmptyLeadingMulti,
"---" "\n"
"# 1" "\n"
"---" "\n"
"# 2" "\n"
"---" "\n"
"# 3" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=COMM #[LEADING] 2" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 2", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValNoComent,
"---" "\n"
"foo" "\n"
"---" "\n"
"bar" "\n"
"---" "\n"
"baz" "\n"
,//-----------------------------------------------
"--- foo" "\n"
"--- bar" "\n"
"--- baz" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :bar" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :baz" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("bar"));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("baz"));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValTrailingMulti,
"---" "\n"
"foo # 1" "\n"
"---" "\n"
"bar # 2" "\n"
"---" "\n"
"baz # 3" "\n"
,//-----------------------------------------------
"--- foo # 1" "\n"
"--- bar # 2" "\n"
"--- baz # 3" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 1" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :bar" "\n"
"=COMM #[TRAILING] 2" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :baz" "\n"
"=COMM #[TRAILING] 3" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_TRAILING));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("bar"));
___(ps.add_comment(" 2", COMM_TRAILING));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("baz"));
___(ps.add_comment(" 3", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamValFooterMulti,
"---" "\n"
"foo" "\n"
"# 1" "\n"
"---" "\n"
"bar" "\n"
"# 2" "\n"
"---" "\n"
"baz" "\n"
"# 3" "\n"
,//-----------------------------------------------
"--- foo" "\n"
"# 1" "\n"
"--- bar" "\n"
"# 2" "\n"
"--- baz" "\n"
"# 3" "\n"
,//-----------------------------------------------
"+STR" "\n"
"+DOC ---" "\n"
"=VAL :foo" "\n"
"=COMM #[FOOTER] 1" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :bar" "\n"
"=COMM #[FOOTER] 2" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=VAL :baz" "\n"
"=COMM #[FOOTER] 3" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 1", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("bar"));
___(ps.add_comment(" 2", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.set_val_scalar_plain("baz"));
___(ps.add_comment(" 3", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(StreamMultiDoc,
"# 1" "\n"
"--- # 2" "\n"
"# 3" "\n"
"foo # 4" "\n"
"# 5" "\n"
"--- # 6" "\n"
"# 7" "\n"
"bar # 8" "\n"
"# 9" "\n"
"--- # 10" "\n"
"# 11" "\n"
"baz # 12" "\n"
"# 13" "\n"
"... # 14" "\n"
"# 15" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC ---" "\n"
"=COMM #[DOC_TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :foo" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[FOOTER] 5" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=COMM #[DOC_TRAILING] 6" "\n"
"=COMM #[LEADING] 7" "\n"
"=VAL :bar" "\n"
"=COMM #[TRAILING] 8" "\n"
"=COMM #[FOOTER] 9" "\n"
"-DOC" "\n"
"+DOC ---" "\n"
"=COMM #[DOC_TRAILING] 10" "\n"
"=COMM #[LEADING] 11" "\n"
"=VAL :baz" "\n"
"=COMM #[TRAILING] 12" "\n"
"=COMM #[FOOTER] 13" "\n"
"-DOC ..." "\n"
"=COMM #[TRAILING] 14" "\n"
"=COMM #[FOOTER] 15" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc_expl());
___(ps.add_comment(" 2", COMM_DOC_TRAILING));
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain("foo"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 6", COMM_DOC_TRAILING));
___(ps.add_comment(" 7", COMM_LEADING));
___(ps.set_val_scalar_plain("bar"));
___(ps.add_comment(" 8", COMM_TRAILING));
___(ps.add_comment(" 9", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 10", COMM_DOC_TRAILING));
___(ps.add_comment(" 11", COMM_LEADING));
___(ps.set_val_scalar_plain("baz"));
___(ps.add_comment(" 12", COMM_TRAILING));
___(ps.add_comment(" 13", COMM_FOOTER));
___(ps.end_doc_expl());
___(ps.add_comment(" 14", COMM_TRAILING));
___(ps.add_comment(" 15", COMM_FOOTER));
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
COMMENT_TEST(Single,
"# single comment\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING] single comment\n"
"=VAL :" "\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" single comment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleNoLeadSpace,
"#single comment\n"
,
"# single comment\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING]single comment\n"
"=VAL :" "\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("single comment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleLeadSpace,
"# single comment\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING] single comment\n"
"=VAL :" "\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" single comment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline0,
"# single" "\n"
"# comment" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] single\\n comment" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" single\n comment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline0NoLeadSpace,
"#single" "\n"
"#comment" "\n"
,
"# single" "\n"
"# comment" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING]single\\ncomment" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("single\ncomment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline0LeadSpace,
"# single" "\n"
"# comment" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] single\\n comment" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" single\n comment", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline1,
"#" "\n"
"# single" "\n"
"# comment" "\n"
"#" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING]\\n single\\n comment\\n" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("\n single\n comment\n", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline1NoLeadSpace,
"#" "\n"
"#single" "\n"
"#comment" "\n"
"#" "\n"
,
"#" "\n"
"# single" "\n"
"# comment" "\n"
"#" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING]\\nsingle\\ncomment\\n" "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("\nsingle\ncomment\n", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline1LeadSpace,
"# " "\n"
"# single" "\n"
"# comment" "\n"
"# " "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] \\n single\\n comment\\n " "\n"
"=VAL :" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" \n single\n comment\n ", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline2,
"#\n"
"#\n"
"# single\n"
"#\n"
"#\n"
"# comment\n"
"#\n"
"#\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING]\\n\\n single\\n\\n\\n comment\\n\\n" "\n"
"=VAL :" "\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("\n\n single\n\n\n comment\n\n", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline3,
"#\n"
"#\n"
"# single \n"
"# \n"
"# \n"
"# comment \n"
"#\n"
"#\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING]\\n\\n single \\n \\n \\n comment \\n\\n\n"
"=VAL :" "\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment("\n\n single \n \n \n comment \n\n", COMM_LEADING));
___(ps.set_val_scalar_plain_empty());
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
COMMENT_TEST(SingleMultiline4Indented1,
"a:\n"
" #\n"
" #\n"
" # single \n"
" # \n"
" # \n"
" # comment \n"
" #\n"
" #\n"
" b\n"
,
"+STR\n"
"+DOC\n"
"+MAP\n"
"=VAL :a\n"
"=COMM #[VAL_LEADING]\\n\\n single \\n \\n \\n comment \\n\\n\n"
"=VAL :b\n"
"-MAP\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_block());
___(ps.set_key_scalar_plain("a"));
___(ps.add_comment("\n\n single \n \n \n comment \n\n", COMM_VAL_LEADING));
___(ps.set_val_scalar_plain("b"));
___(ps.end_map_block());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(SingleMultiline4Indented2,
"a:" "\n"
" b:" "\n"
" c:" "\n"
" #" "\n"
" #" "\n"
" # single " "\n"
" # " "\n"
" # " "\n"
" # comment " "\n"
" #" "\n"
" #" "\n"
" d: " "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+MAP" "\n"
"=VAL :a" "\n"
"+MAP" "\n"
"=VAL :b" "\n"
"+MAP" "\n"
"=VAL :c" "\n"
"+MAP" "\n"
"=COMM #[LEADING]\\n\\n single \\n \\n \\n comment \\n\\n" "\n"
"=VAL :d" "\n"
"=VAL :" "\n"
"-MAP" "\n"
"-MAP" "\n"
"-MAP" "\n"
"-MAP" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_block());
___(ps.set_key_scalar_plain("a"));
___(ps.begin_map_val_block());
___(ps.set_key_scalar_plain("b"));
___(ps.begin_map_val_block());
___(ps.set_key_scalar_plain("c"));
___(ps.begin_map_val_block());
___(ps.add_comment("\n\n single \n \n \n comment \n\n", COMM_LEADING));
___(ps.set_key_scalar_plain("d"));
___(ps.set_val_scalar_plain_empty());
___(ps.end_map_block());
___(ps.end_map_block());
___(ps.end_map_block());
___(ps.end_map_block());
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// The other test executables are written to contain the declarative-style
// YmlTestCases. This executable does not have any but the build setup
// assumes it does, and links with the test lib, which requires an existing
// get_case() function. So this is here to act as placeholder until (if?)
// proper test cases are added here. This was detected in #47 (thanks
// @cburgard).
Case const* get_case(csubstr)
{
return nullptr;
}
} // namespace yml
} // namespace c4

View File

@@ -0,0 +1,829 @@
#include "./test_lib/test_engine.hpp"
// WARNING: don't use raw string literals -- g++-4.8 cannot accept
// them as macro arguments
#ifndef RYML_WITH_COMMENTS
#error this test requires RYML_WITH_COMMENTS to be defined
#endif
namespace c4 {
namespace yml {
constexpr const bool multiline = true;
constexpr const bool singleline = false;
COMMENT_TEST(FlowSeqMinimalBase,
"[" "\n"
" val1," "\n"
" val2" "\n"
"]" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=VAL :val1" "\n"
"=VAL :val2" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_scalar_plain("val1"));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("val2"));
___(ps.end_seq_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMinimalBaseSingleLine1,
"# 1" "\n"
"[val1, val2] # 2" "\n"
"# 3" "\n"
,
"# 1" "\n"
"[val1,val2] # 2" "\n"
" # 3" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=VAL :val1" "\n"
"=VAL :val2" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 2\\n 3" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_scalar_plain("val1"));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("val2"));
___(ps.end_seq_flow(singleline));
___(ps.add_comment(" 2\n 3", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMinimalBaseSingleLine2,
"# 1" "\n"
"[val1,val2] # 2" "\n"
" # 3" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=VAL :val1" "\n"
"=VAL :val2" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 2\\n 3" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_scalar_plain("val1"));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("val2"));
___(ps.end_seq_flow(singleline));
___(ps.add_comment(" 2\n 3", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqSingle0,
"[ # 1" "\n"
" # 2" "\n"
"]" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 1\\n 2" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 1\n 2", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqSingle1,
"[" "\n"
" # 1" "\n"
" # 2" "\n"
"]" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_LEADING] 1\\n 2" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 1\n 2", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMinimal0,
"[" "\n"
" # 1" "\n"
" val1, # 2" "\n"
" # 3" "\n"
" val2 # 4" "\n"
" # 5" "\n"
"]" "\n"
,
"[" "\n"
" # 1" "\n"
" val1, # 2" "\n"
" # 3" "\n"
" val2 # 4" "\n"
" # 5" "\n"
"]" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :val1" "\n"
"=COMM #[TRAILING] 2\\n 3" "\n"
"=VAL :val2" "\n"
"=COMM #[TRAILING] 4\\n 5" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain("val1"));
___(ps.add_comment(" 2\n 3", COMM_TRAILING));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("val2"));
___(ps.add_comment(" 4\n 5", COMM_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMinimal1WithTrailingComma,
"[" "\n"
" # 1" "\n"
" val1, # 2" "\n"
" # 3" "\n"
" val2, # 4" "\n" // note the trailing comma
" # 5" "\n"
"]" "\n"
,
"[" "\n"
" # 1" "\n"
" val1, # 2" "\n"
" # 3" "\n"
" val2 # 4" "\n"
" # 5" "\n"
"]" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :val1" "\n"
"=COMM #[TRAILING] 2\\n 3" "\n"
"=VAL :val2" "\n"
"=COMM #[TRAILING] 4\\n 5" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain("val1"));
___(ps.add_comment(" 2\n 3", COMM_TRAILING));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("val2"));
___(ps.add_comment(" 4\n 5", COMM_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqBasic0,
"# 1" "\n"
"[ # 2" "\n"
" # 3" "\n"
" a, # 6" "\n"
" # 7" "\n"
" b # 10" "\n"
" # 11" "\n"
"] # 12" "\n"
" # 13" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2\\n 3" "\n"
"=VAL :a" "\n"
"=COMM #[TRAILING] 6\\n 7" "\n"
"=VAL :b" "\n"
"=COMM #[TRAILING] 10\\n 11" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 12\\n 13" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2\n 3", COMM_VAL_BRACKET_TRAILING));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 6\n 7", COMM_TRAILING));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 10\n 11", COMM_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 12\n 13", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqBasic1,
"# 1" "\n"
"[ # 2" "\n"
" # 3" "\n"
" a # 4" "\n"
" # 5" "\n"
" , # 6" "\n"
" # 7" "\n"
" b # 8" "\n"
" # 9" "\n"
" , # 10" "\n"
" # 11" "\n"
"] # 12" "\n"
" # 13" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2\\n 3" "\n"
"=VAL :a" "\n"
"=COMM #[VAL_TRAILING] 4\\n 5" "\n"
"=COMM #[TRAILING] 6\\n 7" "\n"
"=VAL :b" "\n"
"=COMM #[VAL_TRAILING] 8\\n 9" "\n"
"=COMM #[TRAILING] 10\\n 11" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 12\\n 13" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2\n 3", COMM_VAL_BRACKET_TRAILING));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 4\n 5", COMM_VAL_TRAILING));
___(ps.add_comment(" 6\n 7", COMM_TRAILING));
___(ps.add_sibling());
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 8\n 9", COMM_VAL_TRAILING));
___(ps.add_comment(" 10\n 11", COMM_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 12\n 13", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqBasic2,
"# 1" "\n"
"[" "\n"
" # 3" "\n"
" a" "\n"
" # 5" "\n"
" ," "\n"
" # 7" "\n"
" b" "\n"
" # 9" "\n"
" ," "\n"
" # 11" "\n"
"]" "\n"
"# 13" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :a" "\n"
"=COMM #[COMMA_LEADING] 5" "\n"
"=COMM #[LEADING] 7" "\n"
"=VAL :b" "\n"
"=COMM #[COMMA_LEADING] 9" "\n"
"=COMM #[VAL_BRACKET_LEADING] 11" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 13" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 5", COMM_COMMA_LEADING));
___(ps.add_sibling());
___(ps.add_comment(" 7", COMM_LEADING));
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 9", COMM_COMMA_LEADING));
___(ps.add_comment(" 11", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 13", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMultiline0,
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
,
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
" # 4 footer comment\n"
" # 4 continued\n"
,
"+STR\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+DOC\n"
"+SEQ []\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-SEQ\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\\n 4 footer comment\\n 4 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued\n 4 footer comment\n 4 continued", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMultiline1,
"---\n"
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"[ # 6 bracket trailing comment\n"
" # 6 continued\n"
"] # 7 trailing comment\n"
" # 7 continued\n"
"# 8 footer comment\n"
"# 8 continued\n"
,
"---\n"
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
" # 4 footer comment\n"
" # 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"[ # 6 bracket trailing comment\n"
" # 6 continued\n"
"] # 7 trailing comment\n"
" # 7 continued\n"
" # 8 footer comment\n"
" # 8 continued\n"
,
"+STR\n"
"+DOC ---\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+SEQ []\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-SEQ\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\\n 4 footer comment\\n 4 continued\n"
"-DOC\n"
"+DOC ---\n"
"=COMM #[LEADING] 5 leading comment\\n 5 continued\n"
"+SEQ []\n"
"=COMM #[VAL_BRACKET_TRAILING] 6 bracket trailing comment\\n 6 continued\n"
"-SEQ\n"
"=COMM #[TRAILING] 7 trailing comment\\n 7 continued\\n 8 footer comment\\n 8 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued\n 4 footer comment\n 4 continued", COMM_TRAILING));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 5 leading comment\n 5 continued", COMM_LEADING));
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 6 bracket trailing comment\n 6 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 7 trailing comment\n 7 continued\n 8 footer comment\n 8 continued", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqMultiline2,
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"[ # 6 bracket trailing comment\n"
" # 6 continued\n"
"] # 7 trailing comment\n"
" # 7 continued\n"
"# 8 footer comment\n"
"# 8 continued\n"
,
"---\n"
"# 1 leading comment\n"
"# 1 continued\n"
"[ # 2 bracket trailing comment\n"
" # 2 continued\n"
"] # 3 trailing comment\n"
" # 3 continued\n"
" # 4 footer comment\n"
" # 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"[ # 6 bracket trailing comment\n"
" # 6 continued\n"
"] # 7 trailing comment\n"
" # 7 continued\n"
" # 8 footer comment\n"
" # 8 continued\n"
,
"+STR\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+DOC\n"
"+SEQ []\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-SEQ\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\\n 4 footer comment\\n 4 continued\n"
"-DOC\n"
"+DOC ---\n"
"=COMM #[LEADING] 5 leading comment\\n 5 continued\n"
"+SEQ []\n"
"=COMM #[VAL_BRACKET_TRAILING] 6 bracket trailing comment\\n 6 continued\n"
"-SEQ\n"
"=COMM #[TRAILING] 7 trailing comment\\n 7 continued\\n 8 footer comment\\n 8 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued\n 4 footer comment\n 4 continued", COMM_TRAILING));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 5 leading comment\n 5 continued", COMM_LEADING));
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 6 bracket trailing comment\n 6 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 7 trailing comment\n 7 continued\n 8 footer comment\n 8 continued", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
COMMENT_TEST(FlowSeqWithTagAndAnchor1,
"# 1" "\n"
"[ # 2" "\n"
" # 3" "\n"
" &a # 4" "\n"
" # 5" "\n"
" !atag # 6" "\n"
" # 7" "\n"
" a # 8" "\n"
" # 9" "\n"
"] # 10" "\n"
"# 11" "\n"
,
"# 1" "\n"
"[ # 2" "\n"
" # 3" "\n"
" &a # 4" "\n"
" # 5" "\n"
" !atag # 6" "\n"
" # 7" "\n"
" a # 8" "\n"
" # 9" "\n"
"] # 10" "\n"
" # 11" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2\\n 3" "\n"
"=COMM #[VAL_ANCHOR_TRAILING] 4\\n 5" "\n"
"=COMM #[VAL_TAG_TRAILING] 6\\n 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[TRAILING] 8\\n 9" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 10\\n 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 2\n 3", COMM_VAL_BRACKET_TRAILING));
___(ps.set_val_anchor("a"));
___(ps.add_comment(" 4\n 5", COMM_VAL_ANCHOR_TRAILING));
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 6\n 7", COMM_VAL_TAG_TRAILING));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 8\n 9", COMM_TRAILING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 10\n 11", COMM_TRAILING));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqWithTagAndAnchor2,
"# 1" "\n"
"[" "\n"
" # 3" "\n"
" &a" "\n"
" # 5" "\n"
" !atag" "\n"
" # 7" "\n"
" a" "\n"
" # 9" "\n"
"]" "\n"
"# 11" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 3" "\n"
"=COMM #[VAL_TAG_LEADING] 5" "\n"
"=COMM #[VAL_LEADING2] 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[VAL_BRACKET_LEADING] 9" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_anchor("a"));
___(ps.add_comment(" 5", COMM_VAL_TAG_LEADING));
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 7", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 9", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqWithTagAndAnchor3,
"# 1" "\n"
"[" "\n"
" # 3" "\n"
" &a !atag" "\n"
" # 7" "\n"
" a" "\n"
" # 9" "\n"
"]" "\n"
"# 11" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 3" "\n"
"=COMM #[VAL_LEADING2] 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[VAL_BRACKET_LEADING] 9" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_anchor("a"));
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 7", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 9", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqWithTagAndAnchor4,
"# 1" "\n"
"[" "\n"
" &a" "\n"
" # 5" "\n"
" !atag" "\n"
" # 7" "\n"
" a" "\n"
" # 9" "\n"
"]" "\n"
"# 11" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_TAG_LEADING] 5" "\n"
"=COMM #[VAL_LEADING2] 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[VAL_BRACKET_LEADING] 9" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_anchor("a"));
___(ps.add_comment(" 5", COMM_VAL_TAG_LEADING));
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 7", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 9", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowSeqWithTagAndAnchor5,
"# 1" "\n"
"[" "\n"
" !atag" "\n"
" # 5" "\n"
" &a" "\n"
" # 7" "\n"
" a" "\n"
" # 9" "\n"
"]" "\n"
"# 11" "\n"
,
"# 1" "\n"
"[" "\n"
" # 5" "\n"
" &a !atag" "\n"
" # 7" "\n"
" a" "\n"
" # 9" "\n"
"]" "\n"
"# 11" "\n"
,
"+STR" "\n"
"=COMM #[LEADING] 1" "\n"
"+DOC" "\n"
"+SEQ []" "\n"
"=COMM #[LEADING] 5" "\n"
"=COMM #[VAL_LEADING2] 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[VAL_BRACKET_LEADING] 9" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_doc());
___(ps.begin_seq_val_flow());
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 5", COMM_LEADING));
___(ps.set_val_anchor("a"));
___(ps.add_comment(" 7", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 9", COMM_VAL_BRACKET_LEADING));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// The other test executables are written to contain the declarative-style
// YmlTestCases. This executable does not have any but the build setup
// assumes it does, and links with the test lib, which requires an existing
// get_case() function. So this is here to act as placeholder until (if?)
// proper test cases are added here. This was detected in #47 (thanks
// @cburgard).
Case const* get_case(csubstr)
{
return nullptr;
}
} // namespace yml
} // namespace c4

View File

@@ -0,0 +1,575 @@
#include "./test_lib/test_engine.hpp"
// WARNING: don't use raw string literals -- g++-4.8 cannot accept
// them as macro arguments
#ifndef RYML_WITH_COMMENTS
#error this test requires RYML_WITH_COMMENTS to be defined
#endif
namespace c4 {
namespace yml {
constexpr const bool multiline = true;
constexpr const bool singleline = false;
COMMENT_TEST(FlowMapMinimalBase,
"{" "\n"
" key1: val1," "\n"
" key2: val2" "\n"
"}" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+MAP {}" "\n"
"=VAL :key1" "\n"
"=VAL :val1" "\n"
"=VAL :key2" "\n"
"=VAL :val2" "\n"
"-MAP" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.set_key_scalar_plain("key1"));
___(ps.set_val_scalar_plain("val1"));
___(ps.add_sibling());
___(ps.set_key_scalar_plain("key2"));
___(ps.set_val_scalar_plain("val2"));
___(ps.end_map_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapSingle0,
"{ # 1" "\n"
" # 2" "\n"
"}" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 1\\n 2" "\n"
"-MAP" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.add_comment(" 1\n 2", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapSingle1,
"{" "\n"
" # 1" "\n"
" # 2" "\n"
"}" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_LEADING] 1\\n 2" "\n"
"-MAP" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.add_comment(" 1\n 2", COMM_VAL_BRACKET_LEADING));
___(ps.end_map_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapMinimal,
"{" "\n"
" # 1" "\n"
" key1: val1, # 2" "\n"
" # 3" "\n"
" key2: val2 # 4" "\n"
" # 5" "\n"
"}" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+MAP {}" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :key1" "\n"
"=VAL :val1" "\n"
"=COMM #[TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :key2" "\n"
"=VAL :val2" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[VAL_BRACKET_LEADING] 5" "\n"
"-MAP" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_map_val_flow());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_key_scalar_plain("key1"));
___(ps.set_val_scalar_plain("val1"));
___(ps.add_comment(" 2", COMM_TRAILING));
___(ps.add_sibling());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_key_scalar_plain("key2"));
___(ps.set_val_scalar_plain("val2"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_VAL_BRACKET_LEADING));
___(ps.end_map_flow(multiline));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapBasic,
"# 1" "\n"
"{ # 2" "\n"
" # 3" "\n"
" a # 4" "\n"
" # 5" "\n"
" : # 6" "\n"
" # 7" "\n"
" b # 8" "\n"
" # 9" "\n"
"} # 10" "\n"
"# 11" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :a" "\n"
"=COMM #[KEY_TRAILING] 4" "\n"
"=COMM #[COLON_LEADING] 5" "\n"
"=COMM #[COLON_TRAILING] 6" "\n"
"=COMM #[VAL_LEADING] 7" "\n"
"=VAL :b" "\n"
"=COMM #[VAL_TRAILING] 8" "\n"
"=COMM #[FOOTER] 9" "\n"
"-MAP" "\n"
"=COMM #[TRAILING] 10" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2", COMM_VAL_BRACKET_TRAILING));
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_key_scalar_plain("a"));
___(ps.add_comment(" 4", COMM_KEY_TRAILING));
___(ps.add_comment(" 5", COMM_COLON_LEADING));
___(ps.add_comment(" 6", COMM_COLON_TRAILING));
___(ps.add_comment(" 7", COMM_VAL_LEADING));
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 8", COMM_VAL_TRAILING));
___(ps.add_comment(" 9", COMM_FOOTER));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 10", COMM_TRAILING));
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
// equivalent to {!!atag &a a: !!btag &b b}
COMMENT_TEST(FlowMapBasicWithTagAndAnchor,
"# 1" "\n"
"{ # 2" "\n"
" # 3" "\n"
" &a # 4" "\n"
" # 5" "\n"
" !atag # 6" "\n"
" # 7" "\n"
" a # 8" "\n"
" # 9" "\n"
" : # 10" "\n"
" # 11" "\n"
" &b # 12" "\n"
" # 13" "\n"
" !btag # 14" "\n"
" # 15" "\n"
" b # 16" "\n"
" # 17" "\n"
"} # 18" "\n"
"# 19" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 1" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=COMM #[KEY_ANCHOR_TRAILING] 4" "\n"
"=COMM #[KEY_TAG_LEADING] 5" "\n"
"=COMM #[KEY_TAG_TRAILING] 6" "\n"
"=COMM #[KEY_LEADING] 7" "\n"
"=VAL &a <!atag> :a" "\n"
"=COMM #[KEY_TRAILING] 8" "\n"
"=COMM #[COLON_LEADING] 9" "\n"
"=COMM #[COLON_TRAILING] 10" "\n"
"=COMM #[VAL_ANCHOR_LEADING] 11" "\n"
"=COMM #[VAL_ANCHOR_TRAILING] 12" "\n"
"=COMM #[VAL_TAG_LEADING] 13" "\n"
"=COMM #[VAL_TAG_TRAILING] 14" "\n"
"=COMM #[VAL_LEADING2] 15" "\n"
"=VAL &b <!btag> :b" "\n"
"=COMM #[VAL_TRAILING] 16" "\n"
"=COMM #[FOOTER] 17" "\n"
"-MAP" "\n"
"=COMM #[TRAILING] 18" "\n"
"=COMM #[FOOTER] 19" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2", COMM_VAL_BRACKET_TRAILING));
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_key_anchor("a"));
___(ps.add_comment(" 4", COMM_KEY_ANCHOR_TRAILING));
___(ps.add_comment(" 5", COMM_KEY_TAG_LEADING));
___(ps.set_key_tag("!atag"));
___(ps.add_comment(" 6", COMM_KEY_TAG_TRAILING));
___(ps.add_comment(" 7", COMM_KEY_LEADING));
___(ps.set_key_scalar_plain("a"));
___(ps.add_comment(" 8", COMM_KEY_TRAILING));
___(ps.add_comment(" 9", COMM_COLON_LEADING));
___(ps.add_comment(" 10", COMM_COLON_TRAILING));
___(ps.add_comment(" 11", COMM_VAL_ANCHOR_LEADING));
___(ps.set_val_anchor("b"));
___(ps.add_comment(" 12", COMM_VAL_ANCHOR_TRAILING));
___(ps.add_comment(" 13", COMM_VAL_TAG_LEADING));
___(ps.set_val_tag("!btag"));
___(ps.add_comment(" 14", COMM_VAL_TAG_TRAILING));
___(ps.add_comment(" 15", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 16", COMM_VAL_TRAILING));
___(ps.add_comment(" 17", COMM_FOOTER));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 18", COMM_TRAILING));
___(ps.add_comment(" 19", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapMultiline0,
"# 1 leading comment\n"
"# 1 continued\n"
"{ # 2 bracket trailing comment\n"
" # 2 continued\n"
"} # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+MAP {}\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-MAP\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\n"
"=COMM #[FOOTER] 4 footer comment\\n 4 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued", COMM_TRAILING));
___(ps.add_comment(" 4 footer comment\n 4 continued", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapMultiline1,
"---\n"
"# 1 leading comment\n"
"# 1 continued\n"
"{ # 2 bracket trailing comment\n"
" # 2 continued\n"
"} # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"{ # 6 bracket trailing comment\n"
" # 6 continued\n"
"} # 7 trailing comment\n"
" # 7 continued\n"
"# 8 footer comment\n"
"# 8 continued\n"
,
"+STR\n"
"+DOC ---\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+MAP {}\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-MAP\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\n"
"=COMM #[FOOTER] 4 footer comment\\n 4 continued\n"
"-DOC\n"
"+DOC ---\n"
"=COMM #[LEADING] 5 leading comment\\n 5 continued\n"
"+MAP {}\n"
"=COMM #[VAL_BRACKET_TRAILING] 6 bracket trailing comment\\n 6 continued\n"
"-MAP\n"
"=COMM #[TRAILING] 7 trailing comment\\n 7 continued\n"
"=COMM #[FOOTER] 8 footer comment\\n 8 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc_expl());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued", COMM_TRAILING));
___(ps.add_comment(" 4 footer comment\n 4 continued", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 5 leading comment\n 5 continued", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 6 bracket trailing comment\n 6 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 7 trailing comment\n 7 continued", COMM_TRAILING));
___(ps.add_comment(" 8 footer comment\n 8 continued", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMapMultiline2,
"# 1 leading comment\n"
"# 1 continued\n"
"{ # 2 bracket trailing comment\n"
" # 2 continued\n"
"} # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"{ # 6 bracket trailing comment\n"
" # 6 continued\n"
"} # 7 trailing comment\n"
" # 7 continued\n"
"# 8 footer comment\n"
"# 8 continued\n"
,
"---\n"
"# 1 leading comment\n"
"# 1 continued\n"
"{ # 2 bracket trailing comment\n"
" # 2 continued\n"
"} # 3 trailing comment\n"
" # 3 continued\n"
"# 4 footer comment\n"
"# 4 continued\n"
"---\n"
"# 5 leading comment\n"
"# 5 continued\n"
"{ # 6 bracket trailing comment\n"
" # 6 continued\n"
"} # 7 trailing comment\n"
" # 7 continued\n"
"# 8 footer comment\n"
"# 8 continued\n"
,
"+STR\n"
"+DOC\n"
"=COMM #[LEADING] 1 leading comment\\n 1 continued\n"
"+MAP {}\n"
"=COMM #[VAL_BRACKET_TRAILING] 2 bracket trailing comment\\n 2 continued\n"
"-MAP\n"
"=COMM #[TRAILING] 3 trailing comment\\n 3 continued\n"
"=COMM #[FOOTER] 4 footer comment\\n 4 continued\n"
"-DOC\n"
"+DOC ---\n"
"=COMM #[LEADING] 5 leading comment\\n 5 continued\n"
"+MAP {}\n"
"=COMM #[VAL_BRACKET_TRAILING] 6 bracket trailing comment\\n 6 continued\n"
"-MAP\n"
"=COMM #[TRAILING] 7 trailing comment\\n 7 continued\n"
"=COMM #[FOOTER] 8 footer comment\\n 8 continued\n"
"-DOC\n"
"-STR\n")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 1 leading comment\n 1 continued", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 2 bracket trailing comment\n 2 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 3 trailing comment\n 3 continued", COMM_TRAILING));
___(ps.add_comment(" 4 footer comment\n 4 continued", COMM_FOOTER));
___(ps.end_doc());
___(ps.begin_doc_expl());
___(ps.add_comment(" 5 leading comment\n 5 continued", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 6 bracket trailing comment\n 6 continued", COMM_VAL_BRACKET_TRAILING));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 7 trailing comment\n 7 continued", COMM_TRAILING));
___(ps.add_comment(" 8 footer comment\n 8 continued", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(FlowMap1,
"# 0\n"
"{ # 0.1\n"
" # 1\n"
" foo: 0, # 2\n"
" # 3\n"
" bar: 1, # 4\n"
" # 5\n"
" map: { # 6\n"
" # 7\n"
" mapchild: yes # 8\n"
" # 9\n"
" }, # 10\n"
" # 11\n"
" seq: [ # 12\n"
" # 13\n"
" seqchild # 14\n"
" # 15\n"
" ] # 16\n"
" # 17\n"
"} # 18\n"
"# 19\n"
,
""
"+STR" "\n"
"+DOC" "\n"
"=COMM #[LEADING] 0" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 0.1" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :foo" "\n"
"=VAL :0" "\n"
"=COMM #[TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :bar" "\n"
"=VAL :1" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[LEADING] 5" "\n"
"=VAL :map" "\n"
"+MAP {}" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 6" "\n"
"=COMM #[LEADING] 7" "\n"
"=VAL :mapchild" "\n"
"=VAL :yes" "\n"
"=COMM #[TRAILING] 8" "\n"
"=COMM #[FOOTER] 9" "\n"
"-MAP" "\n"
"=COMM #[TRAILING] 10" "\n"
"=COMM #[LEADING] 11" "\n"
"=VAL :seq" "\n"
"+SEQ []" "\n"
"=COMM #[VAL_BRACKET_TRAILING] 12" "\n"
"=COMM #[LEADING] 13" "\n"
"=VAL :seqchild" "\n"
"=COMM #[TRAILING] 14" "\n"
"=COMM #[FOOTER] 15" "\n"
"-SEQ" "\n"
"=COMM #[TRAILING] 16" "\n"
"=COMM #[FOOTER] 17" "\n"
"-MAP" "\n"
"=COMM #[TRAILING] 18" "\n"
"=COMM #[FOOTER] 19" "\n"
"-DOC" "\n"
"-STR" "\n"
"")
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.add_comment(" 0", COMM_LEADING));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 0.1", COMM_VAL_BRACKET_TRAILING));
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_key_scalar_plain("foo"));
___(ps.set_val_scalar_plain("0"));
___(ps.add_comment(" 2", COMM_TRAILING));
___(ps.add_sibling());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_key_scalar_plain("bar"));
___(ps.set_val_scalar_plain("1"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_sibling());
___(ps.add_comment(" 5", COMM_LEADING));
___(ps.set_key_scalar_plain("map"));
___(ps.begin_map_val_flow());
___(ps.add_comment(" 6", COMM_VAL_BRACKET_TRAILING));
___(ps.add_comment(" 7", COMM_LEADING));
___(ps.set_key_scalar_plain("mapchild"));
___(ps.set_val_scalar_plain("yes"));
___(ps.add_comment(" 8", COMM_TRAILING));
___(ps.add_comment(" 9", COMM_FOOTER));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 10", COMM_TRAILING));
___(ps.add_sibling());
___(ps.add_comment(" 11", COMM_LEADING));
___(ps.set_key_scalar_plain("seq"));
___(ps.begin_seq_val_flow());
___(ps.add_comment(" 12", COMM_VAL_BRACKET_TRAILING));
___(ps.add_comment(" 13", COMM_LEADING));
___(ps.set_val_scalar_plain("seqchild"));
___(ps.add_comment(" 14", COMM_TRAILING));
___(ps.add_comment(" 15", COMM_FOOTER));
___(ps.end_seq_flow(multiline));
___(ps.add_comment(" 16", COMM_TRAILING));
___(ps.add_comment(" 17", COMM_FOOTER));
___(ps.end_map_flow(multiline));
___(ps.add_comment(" 18", COMM_TRAILING));
___(ps.add_comment(" 19", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// The other test executables are written to contain the declarative-style
// YmlTestCases. This executable does not have any but the build setup
// assumes it does, and links with the test lib, which requires an existing
// get_case() function. So this is here to act as placeholder until (if?)
// proper test cases are added here. This was detected in #47 (thanks
// @cburgard).
Case const* get_case(csubstr)
{
return nullptr;
}
} // namespace yml
} // namespace c4

View File

@@ -0,0 +1,207 @@
#include "./test_lib/test_engine.hpp"
// WARNING: don't use raw string literals -- g++-4.8 cannot accept
// them as macro arguments
#ifndef RYML_WITH_COMMENTS
#error this test requires RYML_WITH_COMMENTS to be defined
#endif
namespace c4 {
namespace yml {
constexpr const bool multiline = true;
constexpr const bool singleline = false;
COMMENT_TEST(BlockSeqMinimal,
"# 1" "\n"
"- val1 # 2" "\n"
"# 3" "\n"
"- val2 # 4" "\n"
"# 5" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ" "\n"
"=COMM #[LEADING] 1" "\n"
"=VAL :val1" "\n"
"=COMM #[TRAILING] 2" "\n"
"=COMM #[LEADING] 3" "\n"
"=VAL :val2" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[FOOTER] 5" "\n"
"-SEQ" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_block());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.set_val_scalar_plain("val1"));
___(ps.add_comment(" 2", COMM_TRAILING));
___(ps.add_sibling());
___(ps.add_comment(" 3", COMM_LEADING));
___(ps.set_val_scalar_plain("val2"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_FOOTER));
___(ps.end_seq_block());
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(BlockSeqBasic,
"# 1" "\n"
"- # 2" "\n"
" # 3" "\n"
" a # 4" "\n"
" # 5" "\n"
"# 6" "\n"
"- # 7" "\n"
" # 8" "\n"
" b # 9" "\n"
" # 10" "\n"
"# 11" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ" "\n"
"=COMM #[LEADING] 1" "\n"
"=COMM #[VAL_DASH_TRAILING] 2" "\n"
"=COMM #[VAL_LEADING] 3" "\n"
"=VAL :a" "\n"
"=COMM #[TRAILING] 4" "\n"
"=COMM #[FOOTER] 5" "\n"
"=COMM #[LEADING] 6" "\n"
"=COMM #[VAL_DASH_TRAILING] 7\\n 8" "\n"
"=VAL :b" "\n"
"=COMM #[TRAILING] 9" "\n"
"=COMM #[FOOTER] 10" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 11" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_block());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.add_comment(" 2", COMM_VAL_DASH_TRAILING));
___(ps.add_comment(" 3", COMM_VAL_LEADING));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 4", COMM_TRAILING));
___(ps.add_comment(" 5", COMM_FOOTER));
___(ps.add_sibling());
___(ps.add_comment(" 6", COMM_LEADING));
___(ps.add_comment(" 7\n 8", COMM_VAL_DASH_TRAILING));
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 9", COMM_TRAILING));
___(ps.add_comment(" 10", COMM_FOOTER));
___(ps.end_seq_block());
___(ps.add_comment(" 11", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
COMMENT_TEST(BlockSeqBasicWithTagAndAnchor,
"# 1" "\n"
"- # 2" "\n"
" # 3" "\n"
" &aa # 4" "\n"
" # 5" "\n"
" !atag # 6" "\n"
" # 7" "\n"
" a # 8" "\n"
" # 9" "\n"
"# 10" "\n"
"- # 11" "\n"
" # 12" "\n"
" &bb # 13" "\n"
" # 14" "\n"
" !btag # 15" "\n"
" # 16" "\n"
" b # 17" "\n"
" # 18" "\n"
"# 19" "\n"
,
"+STR" "\n"
"+DOC" "\n"
"+SEQ" "\n"
"=COMM #[LEADING] 1" "\n"
"=COMM #[VAL_DASH_TRAILING] 2" "\n"
"=COMM #[VAL_ANCHOR_LEADING] 3" "\n"
"=COMM #[VAL_ANCHOR_TRAILING] 4" "\n"
"=COMM #[VAL_TAG_LEADING] 5" "\n"
"=COMM #[VAL_TAG_TRAILING] 6" "\n"
"=COMM #[VAL_LEADING2] 7" "\n"
"=VAL &aa <!atag> :a" "\n"
"=COMM #[TRAILING] 8" "\n"
"=COMM #[FOOTER] 9" "\n"
"=COMM #[LEADING] 10" "\n"
"=COMM #[VAL_DASH_TRAILING] 11\\n 12" "\n"
"=COMM #[VAL_ANCHOR_TRAILING] 13" "\n"
"=COMM #[VAL_TAG_LEADING] 14" "\n"
"=COMM #[VAL_TAG_TRAILING] 15" "\n"
"=COMM #[VAL_LEADING2] 16" "\n"
"=VAL &bb <!btag> :b" "\n"
"=COMM #[TRAILING] 17" "\n"
"=COMM #[FOOTER] 18" "\n"
"-SEQ" "\n"
"=COMM #[FOOTER] 19" "\n"
"-DOC" "\n"
"-STR" "\n"
)
{
___(ps.begin_stream());
___(ps.begin_doc());
___(ps.begin_seq_val_block());
___(ps.add_comment(" 1", COMM_LEADING));
___(ps.add_comment(" 2", COMM_VAL_DASH_TRAILING));
___(ps.add_comment(" 3", COMM_VAL_ANCHOR_LEADING));
___(ps.set_val_anchor("aa"));
___(ps.add_comment(" 4", COMM_VAL_ANCHOR_TRAILING));
___(ps.add_comment(" 5", COMM_VAL_TAG_LEADING));
___(ps.set_val_tag("!atag"));
___(ps.add_comment(" 6", COMM_VAL_TAG_TRAILING));
___(ps.add_comment(" 7", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("a"));
___(ps.add_comment(" 8", COMM_TRAILING));
___(ps.add_comment(" 9", COMM_FOOTER));
___(ps.add_sibling());
___(ps.add_comment(" 10", COMM_LEADING));
___(ps.add_comment(" 11\n 12", COMM_VAL_DASH_TRAILING));
___(ps.set_val_anchor("bb"));
___(ps.add_comment(" 13", COMM_VAL_ANCHOR_TRAILING));
___(ps.add_comment(" 14", COMM_VAL_TAG_LEADING));
___(ps.set_val_tag("!btag"));
___(ps.add_comment(" 15", COMM_VAL_TAG_TRAILING));
___(ps.add_comment(" 16", COMM_VAL_LEADING2));
___(ps.set_val_scalar_plain("b"));
___(ps.add_comment(" 17", COMM_TRAILING));
___(ps.add_comment(" 18", COMM_FOOTER));
___(ps.end_seq_block());
___(ps.add_comment(" 19", COMM_FOOTER));
___(ps.end_doc());
___(ps.end_stream());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// The other test executables are written to contain the declarative-style
// YmlTestCases. This executable does not have any but the build setup
// assumes it does, and links with the test lib, which requires an existing
// get_case() function. So this is here to act as placeholder until (if?)
// proper test cases are added here. This was detected in #47 (thanks
// @cburgard).
Case const* get_case(csubstr)
{
return nullptr;
}
} // namespace yml
} // namespace c4

File diff suppressed because it is too large Load Diff

View File

@@ -118,6 +118,48 @@ void test_compare(Tree const& actual, id_type node_actual,
EXPECT_EQ(actual.val_anchor(node_actual), expected.val_anchor(node_expected));
}
#ifdef RYML_WITH_COMMENTS
struct comment_type_info { comment_data_type type; const char* name; comment_data_type bit; };
static const comment_type_info comment_types[] = {
#define _c4comm(comm_symbol, bit) {COMM_##comm_symbol, "COMM_" #comm_symbol, bit},
_RYML_DEFINE_COMMENTS(_c4comm)
#undef _c4comm
{COMM_NONE,"COMM_NONE", 0},
{COMM_ANY,"COMM_ANY", COMM_LAST_},
};
auto getnfo = [](comment_data_type type){
for(comment_type_info const& nfo : comment_types)
if(nfo.type == type)
return nfo;
return comment_type_info{};
};
for(comment_type_info nfo : comment_types)
{
RYML_TRACE_FMT("type={}(bit {}): {}", nfo.type, nfo.bit, to_csubstr(nfo.name));
bool is_power_of_two = ((nfo.type & (nfo.type - 1)) == 0);
ASSERT_TRUE(is_power_of_two || nfo.type == 0 || nfo.type == COMM_ANY);
CommentData const* actual_comment = actual.comment(node_actual, nfo.type);
CommentData const* expected_comment = expected.comment(node_expected, nfo.type);
comment_type_info actual_nfo = getnfo(actual_comment ? actual_comment->m_type : nfo.type);
comment_type_info expected_nfo = getnfo(expected_comment ? expected_comment->m_type : nfo.type);
RYML_TRACE_FMT("{}={}(bit {}): {}: {}", actual_name, actual_nfo.type, actual_nfo.bit, actual_nfo.name, actual_comment ? actual_comment->m_text : csubstr("<none>"));
RYML_TRACE_FMT("{}={}(bit {}): {}: {}", expected_name, expected_nfo.type, expected_nfo.bit, expected_nfo.name, expected_comment ? expected_comment->m_text : csubstr("<none>"));
if(is_power_of_two && actual_comment) { EXPECT_EQ(actual_comment->m_type, nfo.type); }
if(is_power_of_two && expected_comment) { EXPECT_EQ(expected_comment->m_type, nfo.type); }
EXPECT_TRUE(bool(actual_comment) == bool(expected_comment));
if(actual_comment && expected_comment)
{
if((actual_comment->m_type != expected_comment->m_type)
||
(actual_comment->m_text != expected_comment->m_text))
{
EXPECT_EQ(actual_comment->m_type, expected_comment->m_type);
EXPECT_EQ(actual_comment->m_text, expected_comment->m_text);
}
}
}
#endif
EXPECT_EQ(actual.num_children(node_actual), expected.num_children(node_expected));
for(id_type ia = actual.first_child(node_actual), ib = expected.first_child(node_expected);
ia != NONE && ib != NONE;
@@ -158,6 +200,8 @@ void test_arena_not_shared(Tree const& a, Tree const& b)
EXPECT_FALSE(a.in_arena(td.handle));
EXPECT_FALSE(a.in_arena(td.prefix));
}
#ifdef RYML_WITH_COMMENTS
#endif
}
@@ -628,6 +672,160 @@ void print_test_tree(const char *message, TestCaseNode const& t)
printf("--------------------------------------\n");
}
void test_comment_invariants(Tree const& t, id_type id)
{
id = id != NONE ? id : t.root_id();
(void)id;
#ifdef RYML_WITH_COMMENTS
SCOPED_TRACE("comment invariants");
RYML_TRACE_FMT("id={}", id);
if(t.m_comments_cap == 0)
{
ASSERT_EQ(t.m_comments_buf, nullptr);
ASSERT_EQ(t.m_comments_size, 0);
ASSERT_EQ(t._p(id)->m_first_comment, NONE);
ASSERT_EQ(t._p(id)->m_last_comment, NONE);
return;
}
ASSERT_NE(t.m_comments_buf, nullptr);
ASSERT_LE(t.m_comments_size, t.m_comments_cap);
struct comm_nfo { CommentType_e type; csubstr name; };
const comm_nfo all_comments[] = {
#define _c4comm(comm_symbol, bit) {COMM_##comm_symbol, #comm_symbol},
_RYML_DEFINE_COMMENTS(_c4comm)
#undef _c4comm
};
auto get_nfo = [&](CommentType_e type) {
for(comm_nfo nfo : all_comments)
if(nfo.type == type)
return nfo;
return comm_nfo{};
};
id_type count_iter = 0;
NodeData const* node = t._p(id);
if(node->m_first_comment == NONE || node->m_last_comment == NONE)
{
EXPECT_EQ(node->m_first_comment, NONE);
EXPECT_EQ(node->m_last_comment, NONE);
}
else
{
ASSERT_LT(node->m_first_comment, t.m_comments_size);
ASSERT_LT(node->m_last_comment, t.m_comments_size);
EXPECT_EQ(t.m_comments_buf[node->m_first_comment].m_prev, NONE);
EXPECT_EQ(t.m_comments_buf[node->m_last_comment].m_next, NONE);
for(id_type cid = node->m_first_comment; cid != NONE; cid = t.m_comments_buf[cid].m_next)
{
CommentData const* comm = &t.m_comments_buf[cid];
RYML_TRACE_FMT("cid={} {}({})", cid, get_nfo(comm->m_type).name, c4::fmt::hex((comment_data_type)comm->m_type));
ASSERT_LT(cid, t.m_comments_size);
EXPECT_EQ(t.comment(id, comm->m_type), comm);
if(comm->m_prev != NONE)
{
EXPECT_NE(cid, node->m_first_comment);
ASSERT_LT(comm->m_prev, t.m_comments_size);
CommentData const* prev = &t.m_comments_buf[comm->m_prev];
EXPECT_LT(prev->m_type, comm->m_type);
EXPECT_EQ(prev->m_next, cid);
}
else
{
EXPECT_EQ(cid, node->m_first_comment);
}
if(comm->m_next != NONE)
{
EXPECT_NE(cid, node->m_last_comment);
ASSERT_LT(comm->m_next, t.m_comments_size);
CommentData const* next = &t.m_comments_buf[comm->m_next];
EXPECT_GT(next->m_type, comm->m_type);
EXPECT_EQ(next->m_prev, cid);
}
else
{
EXPECT_EQ(cid, node->m_last_comment);
}
++count_iter;
}
}
id_type count_get = 0;
{
CommentData const* prev = nullptr;
comm_nfo nfo_prev = {COMM_NONE, "NONE"};
for(comm_nfo nfo : all_comments)
{
RYML_TRACE_FMT("comm={}({})", nfo.name, c4::fmt::hex((comment_data_type)nfo.type));
CommentData const* comm = t.comment(id, nfo.type);
if(nfo_prev.type != COMM_NONE)
{
RYML_TRACE_FMT("ctype_prev={}({})", nfo_prev.name, c4::fmt::hex((comment_data_type)nfo_prev.type));
ASSERT_GE(nfo.type, nfo_prev.type);
EXPECT_EQ(comm, t.comment(id, prev, nfo.type));
}
else
{
EXPECT_EQ(comm, t.comment(id, prev, nfo.type));
}
count_get += !!comm;
nfo_prev = nfo;
prev = comm;
}
}
EXPECT_EQ(count_iter, count_get);
size_t num_types = C4_COUNTOF(all_comments);
for(size_t i = 0; i < num_types; ++i)
{
comm_nfo nfo = all_comments[i];
RYML_TRACE_FMT("comm[{}]={}({})", i, nfo.name, c4::fmt::hex((comment_data_type)nfo.type));
ASSERT_EQ(nfo.type & (nfo.type - 1u), 0u); // must be power of two (ie, single bit)
CommentType_e mask_lower_without = CommentType_e(nfo.type - 1u); // all bits up to this comment (exclusive)
CommentType_e mask_lower_with = CommentType_e((((uint32_t)nfo.type) << 1u) - 1u); // all bits up to this comment (inclusive)
CommentType_e mask_upper_without = CommentType_e(COMM_ANY & ~mask_lower_with); // all bits
CommentData const* comm = t.comment(id, nfo.type);
if(comm)
{
EXPECT_NE(t.comment(id, mask_lower_without), comm);
EXPECT_NE(t.comment(id, mask_upper_without), comm);
}
for(size_t j = 0; j < i; ++j)
{
comm_nfo lo = all_comments[j];
comm_nfo hi = nfo;
RYML_TRACE_FMT("lo[{}]={}({})", j, lo.name, c4::fmt::hex((comment_data_type)lo.type));
RYML_TRACE_FMT("hi[{}]={}({})", i, hi.name, c4::fmt::hex((comment_data_type)hi.type));
CommentData const* comm_lo = t.comment(id, lo.type);
CommentData const* comm_hi = t.comment(id, hi.type);
EXPECT_EQ(t.comment(id, comm_lo, hi.type), comm_hi);
}
for(size_t j = i+1; j < num_types; ++j)
{
comm_nfo lo = nfo;
comm_nfo hi = all_comments[j];
RYML_TRACE_FMT("lo[{}]={}({})", j, lo.name, c4::fmt::hex((comment_data_type)lo.type));
RYML_TRACE_FMT("hi[{}]={}({})", i, hi.name, c4::fmt::hex((comment_data_type)hi.type));
CommentData const* comm_lo = t.comment(id, lo.type);
CommentData const* comm_hi = t.comment(id, hi.type);
EXPECT_EQ(t.comment(id, comm_lo, hi.type), comm_hi);
}
}
for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(id))
{
test_comment_invariants(t, child);
}
#endif
}
void test_comment_invariants(ConstNodeRef const &n)
{
ASSERT_TRUE(n.readable());
test_comment_invariants(*n.tree(), n.id());
}
void test_invariants(ConstNodeRef const& n)
{
SCOPED_TRACE(n.id());
@@ -650,6 +848,8 @@ void test_invariants(ConstNodeRef const& n)
{
EXPECT_TRUE(n.has_sibling(s));
EXPECT_TRUE(s.has_sibling(n));
if(s.has_key() && !n.has_key()) { EXPECT_EQ(n.type(), NOTYPE); _RYML_WITH_COMMENTS(EXPECT_NE(n.comment(), nullptr)); }
if(!s.has_key() && n.has_key()) { EXPECT_EQ(s.type(), NOTYPE); _RYML_WITH_COMMENTS(EXPECT_NE(s.comment(), nullptr)); }
if(n.has_key() && s.has_key())
{
EXPECT_TRUE(n.has_sibling(s.key()));
@@ -812,6 +1012,7 @@ void test_invariants(Tree const& t)
check_invariants(t);
test_invariants(t.rootref());
test_comment_invariants(t);
if(!testing::UnitTest::GetInstance()->current_test_info()->result()->Passed())
{

View File

@@ -127,6 +127,11 @@ void test_arena_not_shared(Tree const& a, Tree const& b);
void test_invariants(Tree const& t);
void test_invariants(ConstNodeRef const& n);
#ifdef RYML_WITH_COMMENTS
void test_comment_invariants(Tree const& t, id_type id=NONE);
void test_comment_invariants(ConstNodeRef const& n);
#endif
void print_test_node(TestCaseNode const& t, int level=0);
void print_test_tree(TestCaseNode const& p, int level=0);
void print_test_tree(const char *message, TestCaseNode const& t);

View File

@@ -222,6 +222,7 @@ void test_engine_roundtrip_from_yaml(EngineEvtTestCase const& test_case, std::st
void test_engine_testsuite_from_yaml_with_comments(EngineEvtTestCase const& test_case)
{
_RYML_WITH_COMMENTS(if(test_case.opts.with_comments()) return;)
if(test_case.test_case_flags & HAS_CONTAINER_KEYS)
return;
if(test_case.test_case_flags & HAS_MULTILINE_SCALAR)
@@ -239,6 +240,7 @@ void test_engine_testsuite_from_yaml_with_comments(EngineEvtTestCase const& test
void test_engine_ints_from_yaml_with_comments(EngineEvtTestCase const& test_case)
{
_RYML_WITH_COMMENTS(if(test_case.opts.with_comments()) return;)
if(test_case.test_case_flags & HAS_MULTILINE_SCALAR)
return;
const auto injected_comment_cases = inject_comments_in_src(test_case.yaml);
@@ -254,6 +256,7 @@ void test_engine_ints_from_yaml_with_comments(EngineEvtTestCase const& test_case
void test_engine_tree_from_yaml_with_comments(EngineEvtTestCase const& test_case)
{
_RYML_WITH_COMMENTS(if(test_case.opts.with_comments()) return;)
if(test_case.test_case_flags & HAS_CONTAINER_KEYS)
return;
if(test_case.test_case_flags & HAS_MULTILINE_SCALAR)
@@ -271,6 +274,7 @@ void test_engine_tree_from_yaml_with_comments(EngineEvtTestCase const& test_case
void test_engine_roundtrip_from_yaml_with_comments(EngineEvtTestCase const& test_case)
{
_RYML_WITH_COMMENTS(if(test_case.opts.with_comments()) return;)
if(test_case.test_case_flags & HAS_CONTAINER_KEYS)
return;
if(test_case.test_case_flags & HAS_MULTILINE_SCALAR)

View File

@@ -117,6 +117,10 @@ struct EventTransformer
fwds(add_directive)
#ifdef RYML_WITH_COMMENTS
void add_comment(csubstr txt, CommentType_e type) { handler.add_comment(transformer(txt), type); }
#endif
#undef fwd
#undef fwds
#undef fwdb
@@ -526,6 +530,15 @@ ENGINE_TEST_DEFINE_CASE(name) \
//-----------------------------------------------------------------------------
#ifdef RYML_WITH_COMMENTS
#define COMMENT_TEST(name, ...) ENGINE_TEST_(name, ParserOptions{}.with_comments(true), __VA_ARGS__)
#else
#define COMMENT_TEST(name, ...) \
template<class Handler> void disabled_##name(Handler &ps); \
template<class Handler> void disabled_##name(Handler &ps)
#endif
/* declare a parse engine test for the existing event handlers.
* The extra arguments are for the ctor of EngineEvtTestCase */
#define ENGINE_TEST(name, ...) ENGINE_TEST_(name, ParserOptions{}, __VA_ARGS__)

View File

@@ -122,6 +122,12 @@ void test_events_ints_invariants(csubstr parsed_yaml,
prev = (evt & ievt::PSTR) ? evts[evtpos - 3] : evts[evtpos - 1];
if(nextpos < evts_sz)
next = evts[nextpos];
if(evt & ievt::COMM)
evt &= ievt::_COMM_MASKOUT;
if(prev & ievt::COMM)
prev &= ievt::_COMM_MASKOUT;
if(next & ievt::COMM)
next &= ievt::_COMM_MASKOUT;
#define _test_str_in_buffer(i) \
do { \
EXPECT_LE(i + 3, evts_sz); \

View File

@@ -128,6 +128,7 @@ INSTRUCTIONS:
"src/c4/yml/error.hpp",
"src/c4/yml/error.def.hpp",
"src/c4/yml/node_type.hpp",
"src/c4/yml/comment_type.hpp",
"src/c4/yml/tag.hpp",
am.onlyif(has_evt(Event.tree), "src/c4/yml/tree.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/node.hpp"),