3rdparty: Update rapidyaml to v0.10.0

Signed-off-by: SternXD <stern@sidestore.io>
This commit is contained in:
SternXD 2025-11-26 14:17:32 -05:00 committed by Ty
parent ee6b080fa2
commit 3d2ecafb01
26 changed files with 431 additions and 293 deletions

View File

@ -30,7 +30,7 @@ add_library(pcsx2-rapidyaml
include/c4/windows_pop.hpp
include/c4/windows_push.hpp
include/c4/yml/common.hpp
include/c4/yml/detail/parser_dbg.hpp
include/c4/yml/detail/dbgprint.hpp
include/c4/yml/detail/stack.hpp
include/c4/yml/emit.def.hpp
include/c4/yml/emit.hpp

View File

@ -24,7 +24,7 @@
/** @see http://sourceforge.net/p/predef/wiki/Compilers/ for a list of compiler identifier macros */
/** @see https://msdn.microsoft.com/en-us/library/b0084kay.aspx for VS2013 predefined macros */
#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
# define C4_MSVC
# define C4_MSVC_VERSION_2022 17
# define C4_MSVC_VERSION_2019 16

View File

@ -561,7 +561,7 @@ template<class T>
C4_ALWAYS_INLINE auto _format_dump_compute_size(T const& v)
-> typename std::enable_if<!dump_directly<T>::value, size_t>::type
{
return to_chars({}, v);
return to_chars(substr{}, v);
}
template<class Arg, class... Args>
size_t _format_dump_compute_size(Arg const& a, Args const& ...more)

View File

@ -24,7 +24,7 @@ C4_ALWAYS_INLINE c4::substr to_substr(std::string &s) noexcept
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::substr(&s[0], s.size());
return c4::substr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
/** get a readonly view to an existing std::string.
@ -38,7 +38,7 @@ C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string const& s) noexcept
#error this function will have undefined behavior
#endif
// since c++11 it is legal to call s[s.size()].
return c4::csubstr(&s[0], s.size());
return c4::csubstr(&s[0], s.size()); // NOLINT(readability-container-data-pointer)
}
//-----------------------------------------------------------------------------
@ -87,7 +87,7 @@ inline bool from_chars(c4::csubstr buf, std::string * s)
if(buf.len)
{
C4_ASSERT(buf.str != nullptr);
memcpy(&(*s)[0], buf.str, buf.len);
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}

View File

@ -78,7 +78,7 @@ inline bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s)
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
if(buf.len > 0)
{
memcpy(&(*s)[0], buf.str, buf.len);
memcpy(&(*s)[0], buf.str, buf.len); // NOLINT(readability-container-data-pointer)
}
return true;
}

View File

@ -5,6 +5,8 @@
#include <cstddef>
// NOLINTBEGIN(cert-dcl58-cpp)
// forward declarations for std::vector
#if defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_MSC_VER)
#if defined(_MSC_VER)
@ -63,4 +65,6 @@ template<class Alloc> bool from_chars(c4::csubstr buf, std::vector<char, Alloc>
} // namespace c4
// NOLINTEND(cert-dcl58-cpp)
#endif // _C4_STD_VECTOR_FWD_HPP_

View File

@ -61,10 +61,10 @@ C4CORE_EXPORT substr decode_code_point(substr out, csubstr code_point);
* @param code: the code point must have length in ]0,8], and must not begin
* with any of `U+`,`\\x`,`\\u,`\\U`,`0` (asserted)
*
* @return the part of @p out that was written, which will always be
* @return the number of written characters, which will always be
* at most 4 bytes.
*/
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, uint32_t code);
C4CORE_EXPORT size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, uint32_t code);
/** @} */

View File

@ -9,7 +9,7 @@
#include <c4/dump.hpp>
#include <c4/yml/export.hpp>
#if defined(C4_MSVC) || defined(C4_MINGW)
#if defined(C4_MSVC) || defined(C4_MINGW) || defined(_WIN32) || defined(C4_WIN)
#include <malloc.h>
#else
#include <alloca.h>
@ -288,7 +288,8 @@ struct RYML_EXPORT LineCol
//! construct from offset, line and column
LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
};
static_assert(std::is_trivial<LineCol>::value, "LineCol not trivial");
static_assert(std::is_trivially_copyable<LineCol>::value, "LineCol not trivially copyable");
static_assert(std::is_trivially_default_constructible<LineCol>::value, "LineCol not trivially default constructible");
static_assert(std::is_standard_layout<LineCol>::value, "Location not trivial");

View File

@ -1,5 +1,5 @@
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
#define _C4_YML_DETAIL_PARSER_DBG_HPP_
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#define _C4_YML_DETAIL_DBGPRINT_HPP_
#ifndef _C4_YML_COMMON_HPP_
#include "../common.hpp"
@ -11,22 +11,9 @@
//-----------------------------------------------------------------------------
// some debugging scaffolds
// NOLINTBEGIN(*)
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
C4_SUPPRESS_WARNING_MSVC_PUSH
C4_SUPPRESS_WARNING_MSVC(4068/*unknown pragma*/)
#pragma GCC system_header
C4_SUPPRESS_WARNING_GCC("-Wunknown-pragmas")
C4_SUPPRESS_WARNING_CLANG("-Wgnu-zero-variadic-macro-arguments")
// NOLINTEND(*)
// debug prints
#ifndef RYML_DBG
# define _c4err(fmt, ...) \
this->_err("ERROR: " fmt, ## __VA_ARGS__)
# define _c4dbgt(fmt, ...)
# define _c4dbgpf(fmt, ...)
# define _c4dbgpf_(fmt, ...)
@ -36,14 +23,12 @@ C4_SUPPRESS_WARNING_CLANG("-Wgnu-zero-variadic-macro-arguments")
# define _c4presc(...)
# define _c4prscalar(msg, scalar, keep_newlines)
#else
# define _c4err(fmt, ...) \
do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, ## __VA_ARGS__); } while(0)
# define _c4dbgt(fmt, ...) do { if(_dbg_enabled()) { \
this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__); } } while(0)
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__)
# define _c4dbgpf_(fmt, ...) _dbg_printf("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__)
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
# define _c4dbgp_(msg) _dbg_printf("{}:{}: " msg , __FILE__, __LINE__ )
this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__); } } while(0)
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgpf_(fmt, ...) _dbg_printf("{}:{}: " fmt , __FILE__, __LINE__, __VA_ARGS__)
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
# define _c4dbgp_(msg) _dbg_printf("{}:{}: " msg , __FILE__, __LINE__ )
# define _c4dbgq(msg) _dbg_printf(msg "\n")
# define _c4presc(...) do { if(_dbg_enabled()) __c4presc(__VA_ARGS__); } while(0)
# define _c4prscalar(msg, scalar, keep_newlines) \
@ -141,7 +126,4 @@ inline void __c4presc(csubstr s, bool keep_newlines=false)
#endif // RYML_DBG
C4_SUPPRESS_WARNING_GCC_CLANG_POP
C4_SUPPRESS_WARNING_MSVC_POP
#endif /* _C4_YML_DETAIL_PARSER_DBG_HPP_ */
#endif /* _C4_YML_DETAIL_DBGPRINT_HPP_ */

View File

@ -6,8 +6,8 @@
#endif
/** @file emit.def.hpp Definitions for emit functions. */
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
#include "c4/yml/detail/parser_dbg.hpp"
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#include "c4/yml/detail/dbgprint.hpp"
#endif
namespace c4 {

View File

@ -9,8 +9,8 @@
#include "c4/yml/node_type.hpp"
#endif
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
#include "c4/yml/detail/parser_dbg.hpp"
#ifndef _C4_YML_DETAIL_DBGPRINT_HPP_
#include "c4/yml/detail/dbgprint.hpp"
#endif
#ifndef _C4_YML_PARSER_STATE_HPP_

View File

@ -19,11 +19,12 @@ namespace yml {
* @{ */
/** The stack state needed specifically by @ref EventHandlerTree */
/** @cond dev */
struct EventHandlerTreeState : public ParserState
{
NodeData *tr_data;
};
/** @endcond */
/** The event handler to create a ryml @ref Tree. See the
@ -463,9 +464,8 @@ public:
{
_c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(KEYREF)))
_RYML_CB_ERR_(m_tree->callbacks(), "key cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), !anchor.begins_with('&'));
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(KEYREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(KEYANCH);
m_curr->tr_data->m_key.anchor = anchor;
}
@ -473,9 +473,8 @@ public:
{
_c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
_RYML_CB_ASSERT(m_stack.m_callbacks, m_tree);
if(C4_UNLIKELY(_has_any_(VALREF)))
_RYML_CB_ERR_(m_tree->callbacks(), "val cannot have both anchor and ref", m_curr->pos);
_RYML_CB_ASSERT(m_tree->callbacks(), !anchor.begins_with('&'));
_RYML_CB_ASSERT(m_stack.m_callbacks, !_has_any_(VALREF));
_RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with('&'));
_enable_(VALANCH);
m_curr->tr_data->m_val.anchor = anchor;
}

View File

@ -5,7 +5,7 @@
#ifdef RYML_DBG
#include "c4/charconv.hpp"
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#endif
namespace c4 {

View File

@ -260,7 +260,7 @@ public:
public:
/** @name node container+scalar style predicates */
/** @name style predicates */
/** @{ */
// documentation to the right -->
@ -269,6 +269,9 @@ public:
C4_ALWAYS_INLINE bool type_has_all(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_all(id_, bits); } /**< Forward to @ref Tree::type_has_all(). Node must be readable. */
C4_ALWAYS_INLINE bool type_has_none(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_none(id_, bits); } /**< Forward to @ref Tree::type_has_none(). Node must be readable. */
C4_ALWAYS_INLINE NodeType key_style() const RYML_NOEXCEPT { _C4RR(); return tree_->key_style(id_); } /**< Forward to @ref Tree::key_style(). Node must be readable. */
C4_ALWAYS_INLINE NodeType val_style() const RYML_NOEXCEPT { _C4RR(); return tree_->val_style(id_); } /**< Forward to @ref Tree::val_style(). Node must be readable. */
C4_ALWAYS_INLINE bool is_container_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container_styled(id_); } /**< Forward to @ref Tree::is_container_styled(). Node must be readable. */
C4_ALWAYS_INLINE bool is_block() const RYML_NOEXCEPT { _C4RR(); return tree_->is_block(id_); } /**< Forward to @ref Tree::is_block(). Node must be readable. */
C4_ALWAYS_INLINE bool is_flow_sl() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow_sl(id_); } /**< Forward to @ref Tree::is_flow_sl(). Node must be readable. */
@ -608,6 +611,19 @@ public:
/** @} */
public:
/** @name locations */
/** @{ */
Location location(Parser const& parser) const
{
_C4RR();
return tree_->location(parser, id_);
}
/** @} */
public:
/** @name deserialization */
@ -881,7 +897,6 @@ public:
ConstNodeRef& operator= (NodeRef const&) noexcept;
ConstNodeRef& operator= (NodeRef &&) noexcept;
/** @} */
public:
@ -1128,6 +1143,14 @@ public:
void set_container_style(NodeType_e style) { _C4RR(); m_tree->set_container_style(m_id, style); }
void set_key_style(NodeType_e style) { _C4RR(); m_tree->set_key_style(m_id, style); }
void set_val_style(NodeType_e style) { _C4RR(); m_tree->set_val_style(m_id, style); }
void clear_style(bool recurse=false) { _C4RR(); m_tree->clear_style(m_id, recurse); }
void set_style_conditionally(NodeType type_mask,
NodeType rem_style_flags,
NodeType add_style_flags,
bool recurse=false)
{
_C4RR(); m_tree->set_style_conditionally(m_id, type_mask, rem_style_flags, add_style_flags, recurse);
}
public:

View File

@ -8,6 +8,9 @@
C4_SUPPRESS_WARNING_MSVC_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
#if __GNUC__ >= 6
C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
#endif
namespace c4 {
namespace yml {
@ -193,7 +196,7 @@ public:
public:
/** @name container+scalar style queries
/** @name style functions
* @{ */
C4_ALWAYS_INLINE bool is_container_styled() const noexcept { return (type & (CONTAINER_STYLE)) != 0; }
@ -218,9 +221,13 @@ public:
C4_ALWAYS_INLINE bool is_val_quoted() const noexcept { return (type & VALQUO) != 0; }
C4_ALWAYS_INLINE bool is_quoted() const noexcept { return (type & (KEYQUO|VALQUO)) != 0; }
C4_ALWAYS_INLINE NodeType key_style() const noexcept { return (type & (KEY_STYLE)); }
C4_ALWAYS_INLINE NodeType val_style() const noexcept { return (type & (VAL_STYLE)); }
C4_ALWAYS_INLINE void set_container_style(NodeType_e style) noexcept { type = ((style & CONTAINER_STYLE) | (type & ~CONTAINER_STYLE)); }
C4_ALWAYS_INLINE void set_key_style(NodeType_e style) noexcept { type = ((style & KEY_STYLE) | (type & ~KEY_STYLE)); }
C4_ALWAYS_INLINE void set_val_style(NodeType_e style) noexcept { type = ((style & VAL_STYLE) | (type & ~VAL_STYLE)); }
C4_ALWAYS_INLINE void clear_style() noexcept { type &= ~STYLE; }
/** @} */

View File

@ -8,11 +8,16 @@
#include <ctype.h>
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#include "c4/yml/filter_processor.hpp"
#ifdef RYML_DBG
#include <c4/dump.hpp>
#include "c4/yml/detail/print.hpp"
#define _c4err_(fmt, ...) do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, __VA_ARGS__); } while(0)
#define _c4err(fmt) do { RYML_DEBUG_BREAK(); this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__); } while(0)
#else
#define _c4err_(fmt, ...) this->_err("ERROR: " fmt, __VA_ARGS__)
#define _c4err(fmt) this->_err("ERROR: {}", fmt)
#endif
@ -796,7 +801,7 @@ bool ParseEngine<EventHandler>::_is_valid_start_scalar_plain_flow(csubstr s)
case '{':
case '[':
//_RYML_WITHOUT_TAB_TOKENS(case '\t'):
_c4err("invalid token \":{}\"", _c4prc(s.str[1]));
_c4err_("invalid token \":{}\"", _c4prc(s.str[1]));
break;
case ' ':
case '}':
@ -831,7 +836,7 @@ bool ParseEngine<EventHandler>::_is_valid_start_scalar_plain_flow(csubstr s)
case '}':
case '[':
case ']':
_c4err("invalid token \"?{}\"", _c4prc(s.str[1]));
_c4err_("invalid token \"?{}\"", _c4prc(s.str[1]));
break;
default:
break;
@ -945,7 +950,7 @@ bool ParseEngine<EventHandler>::_scan_scalar_plain_seq_flow(ScannedScalar *C4_RE
case '{':
case '}':
_line_progressed(i);
_c4err("invalid character: '{}'", c); // noreturn
_c4err_("invalid character: '{}'", c); // noreturn
default:
;
}
@ -1021,14 +1026,14 @@ bool ParseEngine<EventHandler>::_scan_scalar_plain_map_flow(ScannedScalar *C4_RE
case '{':
case '[':
_line_progressed(i);
_c4err("invalid character: '{}'", c); // noreturn
_c4err_("invalid character: '{}'", c); // noreturn
break;
case ']':
_line_progressed(i);
if(has_any(RSEQIMAP))
goto ended_scalar;
else
_c4err("invalid character: '{}'", c); // noreturn
_c4err_("invalid character: '{}'", c); // noreturn
break;
case '#':
if(!i || s.str[i-1] == ' ' _RYML_WITH_TAB_TOKENS(|| s.str[i-1] == '\t'))
@ -2661,45 +2666,50 @@ void ParseEngine<EventHandler>::_filter_dquoted_backslash(FilterProcessor &C4_RE
{
proc.translate_esc('\\');
}
else if(next == 'x') // UTF8
else if(next == 'x') // 2-digit Unicode escape (\xXX), code point 0x000xFF
{
if(C4_UNLIKELY(proc.rpos + 1u + 2u >= proc.src.len))
_c4err("\\x requires 2 hex digits. scalar pos={}", proc.rpos);
_c4err_("\\x requires 2 hex digits. scalar pos={}", proc.rpos);
char readbuf[8];
csubstr codepoint = proc.src.sub(proc.rpos + 2u, 2u);
_c4dbgfdq("utf8 ~~~{}~~~ rpos={} rem=~~~{}~~~", codepoint, proc.rpos, proc.src.sub(proc.rpos));
uint8_t byteval = {};
if(C4_UNLIKELY(!read_hex(codepoint, &byteval)))
_c4err("failed to read \\x codepoint. scalar pos={}", proc.rpos);
proc.translate_esc_bulk((const char*)&byteval, 1u, /*nread*/3u);
uint32_t codepoint_val = {};
if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val)))
_c4err_("failed to read \\x codepoint. scalar pos={}", proc.rpos);
const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val);
if(C4_UNLIKELY(numbytes == 0))
_c4err_("failed to decode code point={}", proc.rpos);
_RYML_CB_ASSERT(callbacks(), numbytes <= 4);
proc.translate_esc_bulk(readbuf, numbytes, /*nread*/3u);
_c4dbgfdq("utf8 after rpos={} rem=~~~{}~~~", proc.rpos, proc.src.sub(proc.rpos));
}
else if(next == 'u') // UTF16
else if(next == 'u') // 4-digit Unicode escape (\uXXXX), code point 0x00000xFFFF
{
if(C4_UNLIKELY(proc.rpos + 1u + 4u >= proc.src.len))
_c4err("\\u requires 4 hex digits. scalar pos={}", proc.rpos);
_c4err_("\\u requires 4 hex digits. scalar pos={}", proc.rpos);
char readbuf[8];
csubstr codepoint = proc.src.sub(proc.rpos + 2u, 4u);
uint32_t codepoint_val = {};
if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val)))
_c4err("failed to parse \\u codepoint. scalar pos={}", proc.rpos);
_c4err_("failed to parse \\u codepoint. scalar pos={}", proc.rpos);
const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val);
if(C4_UNLIKELY(numbytes == 0))
_c4err("failed to decode code point={}", proc.rpos);
_c4err_("failed to decode code point={}", proc.rpos);
_RYML_CB_ASSERT(callbacks(), numbytes <= 4);
proc.translate_esc_bulk(readbuf, numbytes, /*nread*/5u);
}
else if(next == 'U') // UTF32
else if(next == 'U') // 8-digit Unicode escape (\UXXXXXXXX), full 32-bit code point
{
if(C4_UNLIKELY(proc.rpos + 1u + 8u >= proc.src.len))
_c4err("\\U requires 8 hex digits. scalar pos={}", proc.rpos);
_c4err_("\\U requires 8 hex digits. scalar pos={}", proc.rpos);
char readbuf[8];
csubstr codepoint = proc.src.sub(proc.rpos + 2u, 8u);
uint32_t codepoint_val = {};
if(C4_UNLIKELY(!read_hex(codepoint, &codepoint_val)))
_c4err("failed to parse \\U codepoint. scalar pos={}", proc.rpos);
_c4err_("failed to parse \\U codepoint. scalar pos={}", proc.rpos);
const size_t numbytes = decode_code_point((uint8_t*)readbuf, sizeof(readbuf), codepoint_val);
if(C4_UNLIKELY(numbytes == 0))
_c4err("failed to decode code point={}", proc.rpos);
_c4err_("failed to decode code point={}", proc.rpos);
_RYML_CB_ASSERT(callbacks(), numbytes <= 4);
proc.translate_esc_bulk(readbuf, numbytes, /*nread*/9u);
}
@ -2772,7 +2782,7 @@ void ParseEngine<EventHandler>::_filter_dquoted_backslash(FilterProcessor &C4_RE
}
else
{
_c4err("unknown character '{}' after '\\' pos={}", _c4prc(next), proc.rpos);
_c4err_("unknown character '{}' after '\\' pos={}", _c4prc(next), proc.rpos);
}
_c4dbgfdq("backslash...sofar=[{}]~~~{}~~~", proc.wpos, proc.sofar());
}
@ -2849,6 +2859,24 @@ FilterResultExtending ParseEngine<EventHandler>::filter_scalar_dquoted_in_place(
//-----------------------------------------------------------------------------
// block filtering helpers
C4_NO_INLINE inline size_t _find_last_newline_and_larger_indentation(csubstr s, size_t indentation) noexcept
{
if(indentation + 1 > s.len)
return npos;
for(size_t i = s.len-indentation-1; i != size_t(-1); --i)
{
if(s.str[i] == '\n')
{
csubstr rem = s.sub(i + 1);
size_t first = rem.first_not_of(' ');
first = (first != npos) ? first : rem.len;
if(first > indentation)
return i;
}
}
return npos;
}
template<class EventHandler>
template<class FilterProcessor>
void ParseEngine<EventHandler>::_filter_chomp(FilterProcessor &C4_RESTRICT proc, BlockChomp_e chomp, size_t indentation)
@ -3506,37 +3534,67 @@ csubstr ParseEngine<EventHandler>::_filter_scalar_dquot(substr s)
_c4dbgpf("filtering dquo scalar: not enough space: needs {}, have {}", len, s.len);
substr dst = m_evt_handler->alloc_arena(len, &s);
_c4dbgpf("filtering dquo scalar: dst.len={}", dst.len);
_RYML_CB_ASSERT(this->callbacks(), dst.len == len);
FilterResult rsd = this->filter_scalar_dquoted(s, dst);
_c4dbgpf("filtering dquo scalar: ... result now needs {} was {}", rsd.required_len(), len);
_RYML_CB_ASSERT(this->callbacks(), rsd.required_len() <= len); // may be smaller!
_RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, rsd.valid());
_c4dbgpf("filtering dquo scalar: success! s=[{}]~~~{}~~~", rsd.get().len, rsd.get());
return rsd.get();
if(dst.str)
{
_RYML_CB_ASSERT(this->callbacks(), dst.len == len);
FilterResult rsd = this->filter_scalar_dquoted(s, dst);
_c4dbgpf("filtering dquo scalar: ... result now needs {} was {}", rsd.required_len(), len);
_RYML_CB_ASSERT(this->callbacks(), rsd.required_len() <= len); // may be smaller!
_RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, rsd.valid());
_c4dbgpf("filtering dquo scalar: success! s=[{}]~~~{}~~~", rsd.get().len, rsd.get());
return rsd.get();
}
return dst;
}
}
//-----------------------------------------------------------------------------
template<class EventHandler>
csubstr ParseEngine<EventHandler>::_move_scalar_left_and_add_newline(substr s)
{
if(s.is_sub(m_buf))
{
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.str > m_buf.str);
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, s.str-1 >= m_buf.str);
if(s.len)
memmove(s.str - 1, s.str, s.len);
--s.str;
s.str[s.len] = '\n';
++s.len;
return s;
}
else
{
substr dst = m_evt_handler->alloc_arena(s.len + 1);
if(s.len)
memcpy(dst.str, s.str, s.len);
dst[s.len] = '\n';
return dst;
}
}
template<class EventHandler>
csubstr ParseEngine<EventHandler>::_filter_scalar_literal(substr s, size_t indentation, BlockChomp_e chomp)
{
_c4dbgpf("filtering block literal scalar: s=[{}]~~~{}~~~", s.len, s);
FilterResult r = this->filter_scalar_block_literal_in_place(s, s.len, indentation, chomp);
csubstr result;
if(C4_LIKELY(r.valid()))
{
_c4dbgpf("filtering block literal scalar: success! s=[{}]~~~{}~~~", r.get().len, r.get());
return r.get();
result = r.get();
}
else
{
_c4dbgpf("filtering block literal scalar: not enough space: needs {}, have {}", r.required_len(), s.len);
substr dst = m_evt_handler->alloc_arena(r.required_len(), &s);
FilterResult rsd = this->filter_scalar_block_literal(s, dst, indentation, chomp);
_RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, rsd.valid());
_c4dbgpf("filtering block literal scalar: success! s=[{}]~~~{}~~~", rsd.get().len, rsd.get());
return rsd.get();
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, r.required_len() == s.len + 1);
// this can only happen when adding a single newline in clip mode.
// so we shift left the scalar by one place
result = _move_scalar_left_and_add_newline(s);
}
_c4dbgpf("filtering block literal scalar: success! s=[{}]~~~{}~~~", result.len, result);
return result;
}
@ -3546,20 +3604,21 @@ csubstr ParseEngine<EventHandler>::_filter_scalar_folded(substr s, size_t indent
{
_c4dbgpf("filtering block folded scalar: s=[{}]~~~{}~~~", s.len, s);
FilterResult r = this->filter_scalar_block_folded_in_place(s, s.len, indentation, chomp);
csubstr result;
if(C4_LIKELY(r.valid()))
{
_c4dbgpf("filtering block folded scalar: success! s=[{}]~~~{}~~~", r.get().len, r.get());
return r.get();
result = r.get();
}
else
{
_c4dbgpf("filtering block folded scalar: not enough space: needs {}, have {}", r.required_len(), s.len);
substr dst = m_evt_handler->alloc_arena(r.required_len(), &s);
FilterResult rsd = this->filter_scalar_block_folded(s, dst, indentation, chomp);
_RYML_CB_CHECK(m_evt_handler->m_stack.m_callbacks, rsd.valid());
_c4dbgpf("filtering block folded scalar: success! s=[{}]~~~{}~~~", rsd.get().len, rsd.get());
return rsd.get();
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, r.required_len() == s.len + 1);
// this can only happen when adding a single newline in clip mode.
// so we shift left the scalar by one place
result = _move_scalar_left_and_add_newline(s);
}
_c4dbgpf("filtering block folded scalar: success! s=[{}]~~~{}~~~", result.len, result);
return result;
}
@ -3876,119 +3935,6 @@ csubstr ParseEngine<EventHandler>::location_contents(Location const& loc) const
return m_buf.sub(loc.offset);
}
template<class EventHandler>
Location ParseEngine<EventHandler>::location(ConstNodeRef node) const
{
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, node.readable());
return location(*node.tree(), node.id());
}
template<class EventHandler>
Location ParseEngine<EventHandler>::location(Tree const& tree, id_type node) const
{
// try hard to avoid getting the location from a null string.
Location loc;
if(_location_from_node(tree, node, &loc, 0))
return loc;
return val_location(m_buf.str);
}
template<class EventHandler>
bool ParseEngine<EventHandler>::_location_from_node(Tree const& tree, id_type node, Location *C4_RESTRICT loc, id_type level) const
{
if(tree.has_key(node))
{
csubstr k = tree.key(node);
if(C4_LIKELY(k.str != nullptr))
{
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, k.is_sub(m_buf));
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.is_super(k));
*loc = val_location(k.str);
return true;
}
}
if(tree.has_val(node))
{
csubstr v = tree.val(node);
if(C4_LIKELY(v.str != nullptr))
{
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, v.is_sub(m_buf));
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, m_buf.is_super(v));
*loc = val_location(v.str);
return true;
}
}
if(tree.is_container(node))
{
if(_location_from_cont(tree, node, loc))
return true;
}
if(tree.type(node) != NOTYPE && level == 0)
{
// try the prev sibling
{
const id_type prev = tree.prev_sibling(node);
if(prev != NONE)
{
if(_location_from_node(tree, prev, loc, level+1))
return true;
}
}
// try the next sibling
{
const id_type next = tree.next_sibling(node);
if(next != NONE)
{
if(_location_from_node(tree, next, loc, level+1))
return true;
}
}
// try the parent
{
const id_type parent = tree.parent(node);
if(parent != NONE)
{
if(_location_from_node(tree, parent, loc, level+1))
return true;
}
}
}
return false;
}
template<class EventHandler>
bool ParseEngine<EventHandler>::_location_from_cont(Tree const& tree, id_type node, Location *C4_RESTRICT loc) const
{
_RYML_CB_ASSERT(m_evt_handler->m_stack.m_callbacks, tree.is_container(node));
if(!tree.is_stream(node))
{
const char *node_start = tree._p(node)->m_val.scalar.str; // this was stored in the container
if(tree.has_children(node))
{
id_type child = tree.first_child(node);
if(tree.has_key(child))
{
// when a map starts, the container was set after the key
csubstr k = tree.key(child);
if(k.str && node_start > k.str)
node_start = k.str;
}
}
*loc = val_location(node_start);
return true;
}
else // it's a stream
{
*loc = val_location(m_buf.str); // just return the front of the buffer
}
return true;
}
template<class EventHandler>
Location ParseEngine<EventHandler>::val_location(const char *val) const
{
@ -6563,7 +6509,6 @@ mapblck_start:
csubstr maybe_filtered = _maybe_filter_key_scalar_squot(sc); // KEY!
m_evt_handler->set_key_scalar_squoted(maybe_filtered);
_maybe_skip_whitespace_tokens();
_set_indentation(m_evt_handler->m_curr->line_contents.indentation);
// keep the child state on RVAL
addrem_flags(RVAL, RNXT);
}
@ -6604,7 +6549,6 @@ mapblck_start:
csubstr maybe_filtered = _maybe_filter_key_scalar_dquot(sc); // KEY!
m_evt_handler->set_key_scalar_dquoted(maybe_filtered);
_maybe_skip_whitespace_tokens();
_set_indentation(m_evt_handler->m_curr->line_contents.indentation);
// keep the child state on RVAL
addrem_flags(RVAL, RNXT);
}
@ -6666,7 +6610,6 @@ mapblck_start:
csubstr maybe_filtered = _maybe_filter_key_scalar_plain(sc, m_evt_handler->m_curr->indref); // KEY!
m_evt_handler->set_key_scalar_plain(maybe_filtered);
_maybe_skip_whitespace_tokens();
_set_indentation(m_evt_handler->m_curr->line_contents.indentation);
// keep the child state on RVAL
addrem_flags(RVAL, RNXT);
}
@ -6846,7 +6789,6 @@ mapblck_start:
m_evt_handler->begin_map_val_block();
_handle_annotations_and_indentation_after_start_mapblck(startindent, startline);
m_evt_handler->set_key_scalar_plain_empty();
_set_indentation(m_evt_handler->m_curr->line_contents.indentation);
// keep the child state on RVAL
addrem_flags(RVAL, RNXT);
}

View File

@ -1,10 +1,6 @@
#ifndef _C4_YML_PARSE_ENGINE_HPP_
#define _C4_YML_PARSE_ENGINE_HPP_
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
#include "c4/yml/detail/parser_dbg.hpp"
#endif
#ifndef _C4_YML_PARSER_STATE_HPP_
#include "c4/yml/parser_state.hpp"
#endif
@ -41,7 +37,10 @@ namespace yml {
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref EventHandlerYamlStd is the handler responsible for emitting
* - @ref extra::EventHandlerInts parses YAML into an integer array
representation of the tree and scalars.
*
* - @ref extra::EventHandlerTestSuite is the handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project.
@ -103,8 +102,8 @@ namespace yml {
* cases. They are called by the parser when a just-handled
* value/container is actually the first key of a new map:
*
* - `actually_val_is_first_key_of_new_map_flow()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTree" / @ref EventHandlerYamlStd::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerYamlStd")
* - `actually_val_is_first_key_of_new_map_block()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTree" / @ref EventHandlerYamlStd::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerYamlStd")
* - `actually_val_is_first_key_of_new_map_flow()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_flow() "see implementation in EventHandlerTestSuite")
* - `actually_val_is_first_key_of_new_map_block()` (@ref EventHandlerTree::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTree" / @ref EventHandlerTestSuite::actually_val_is_first_key_of_new_map_block() "see implementation in EventHandlerTestSuite")
*
* For example, consider an implicit map inside a seq: `[a: b, c:
* d]` which is parsed as `[{a: b}, {c: d}]`. The standard event
@ -282,11 +281,20 @@ public:
* - @ref EventHandlerTree is the handler responsible for creating the
* ryml @ref Tree
*
* - @ref EventHandlerYamlStd is the handler responsible for emitting
* - @ref extra::EventHandlerTestSuite is a handler responsible for emitting
* standardized [YAML test suite
* events](https://github.com/yaml/yaml-test-suite), used (only) in
* the CI of this project. This is not part of the library and is
* not installed.
*
* - @ref extra::EventHandlerInts is the handler responsible for
* emitting integer-coded events. It is intended for implementing
* fully-conformant parsing in other programming languages
* (integration is currently under work for
* [YamlScript](https://github.com/yaml/yamlscript) and
* [go-yaml](https://github.com/yaml/go-yaml/)). It is not part of
* the library and is not installed.
*
*/
template<class EventHandler>
class ParseEngine
@ -393,8 +401,7 @@ public:
public:
/** @name deprecated parse methods
* @{ */
// deprecated parse methods
/** @cond dev */
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding function in parse.hpp.") typename std::enable_if<U::is_wtree, void>::type parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id);
@ -423,20 +430,15 @@ public:
template<class U=EventHandler> RYML_DEPRECATED("removed, deliberately undefined. use the freestanding csubstr version in parse.hpp.") typename std::enable_if<U::is_wtree, Tree>::type parse_in_arena( substr yaml );
/** @endcond */
/** @} */
public:
/** @name locations */
/** @{ */
/** Get the location of a node of the last tree to be parsed by this parser. */
Location location(Tree const& tree, id_type node_id) const;
/** Get the location of a node of the last tree to be parsed by this parser. */
Location location(ConstNodeRef node) const;
/** Get the string starting at a particular location, to the end
* of the parsed source buffer. */
csubstr location_contents(Location const& loc) const;
/** Given a pointer to a buffer position, get the location.
* @param[in] val must be pointing to somewhere in the source
* buffer that was last parsed by this object. */
@ -444,6 +446,18 @@ public:
/** @} */
public:
/** @cond dev */
template<class U>
RYML_DEPRECATED("moved to Tree::location(Parser const&). deliberately undefined here.")
auto location(Tree const&, id_type node) const -> typename std::enable_if<U::is_wtree, Location>::type;
template<class U>
RYML_DEPRECATED("moved to ConstNodeRef::location(Parser const&), deliberately undefined here.")
auto location(ConstNodeRef const&) const -> typename std::enable_if<U::is_wtree, Location>::type;
/** @endcond */
public:
/** @name scalar filtering */
@ -522,6 +536,7 @@ public: // exposed for testing
csubstr _filter_scalar_dquot(substr s);
csubstr _filter_scalar_literal(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _filter_scalar_folded(substr s, size_t indentation, BlockChomp_e chomp);
csubstr _move_scalar_left_and_add_newline(substr s);
csubstr _maybe_filter_key_scalar_plain(ScannedScalar const& sc, size_t indendation);
csubstr _maybe_filter_val_scalar_plain(ScannedScalar const& sc, size_t indendation);
@ -672,9 +687,6 @@ private:
void _resize_locations(size_t sz);
bool _locations_dirty() const;
bool _location_from_cont(Tree const& tree, id_type node, Location *C4_RESTRICT loc) const;
bool _location_from_node(Tree const& tree, id_type node, Location *C4_RESTRICT loc, id_type level) const;
private:
void _reset();
@ -757,10 +769,6 @@ private:
};
/** @cond dev */
RYML_EXPORT C4_NO_INLINE size_t _find_last_newline_and_larger_indentation(csubstr s, size_t indentation) noexcept;
/** @endcond */
/** Quickly inspect the source to estimate the number of nodes the
* resulting tree is likely have. If a tree is empty before

View File

@ -64,8 +64,7 @@ struct RYML_EXPORT TagDirective
id_type next_node_id;
bool create_from_str(csubstr directive_); ///< leaves next_node_id unfilled
bool create_from_str(csubstr directive_, Tree *tree);
size_t transform(csubstr tag, substr output, Callbacks const& callbacks) const;
size_t transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets=true) const;
};
struct RYML_EXPORT TagDirectiveRange

View File

@ -512,10 +512,19 @@ public:
C4_ALWAYS_INLINE bool is_val_quoted(id_type node) const { return _p(node)->m_type.is_val_quoted(); }
C4_ALWAYS_INLINE bool is_quoted(id_type node) const { return _p(node)->m_type.is_quoted(); }
C4_ALWAYS_INLINE NodeType key_style(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_key(node)); return _p(node)->m_type.key_style(); }
C4_ALWAYS_INLINE NodeType val_style(id_type node) const { _RYML_CB_ASSERT(m_callbacks, has_val(node) || is_root(node)); return _p(node)->m_type.val_style(); }
C4_ALWAYS_INLINE void set_container_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, is_container(node)); _p(node)->m_type.set_container_style(style); }
C4_ALWAYS_INLINE void set_key_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_type.set_key_style(style); }
C4_ALWAYS_INLINE void set_val_style(id_type node, NodeType_e style) { _RYML_CB_ASSERT(m_callbacks, has_val(node)); _p(node)->m_type.set_val_style(style); }
void clear_style(id_type node, bool recurse=false);
void set_style_conditionally(id_type node,
NodeType type_mask,
NodeType rem_style_flags,
NodeType add_style_flags,
bool recurse=false);
/** @} */
public:
@ -580,6 +589,8 @@ public:
* uses a throwaway resolver object. */
void resolve(bool clear_anchors=true);
/** @} */
public:
/** @name tag directives */
@ -766,6 +777,21 @@ public:
/** @} */
public:
/** @name locations */
/** @{ */
/** Get the location of a node from the parse used to parse this tree. */
Location location(Parser const& p, id_type node) const;
private:
bool _location_from_node(Parser const& p, id_type node, Location *C4_RESTRICT loc, id_type level) const;
bool _location_from_cont(Parser const& p, id_type node, Location *C4_RESTRICT loc) const;
/** @} */
public:
/** @name internal string arena */

View File

@ -3,9 +3,9 @@
/** @file version.hpp */
#define RYML_VERSION "0.9.0"
#define RYML_VERSION "0.10.0"
#define RYML_VERSION_MAJOR 0
#define RYML_VERSION_MINOR 9
#define RYML_VERSION_MINOR 10
#define RYML_VERSION_PATCH 0
#include <c4/substr.hpp>

View File

@ -82,7 +82,7 @@
<ClInclude Include="include\c4\windows_push.hpp" />
<ClInclude Include="include\c4\yml\common.hpp" />
<ClInclude Include="include\c4\yml\detail\checks.hpp" />
<ClInclude Include="include\c4\yml\detail\parser_dbg.hpp" />
<ClInclude Include="include\c4\yml\detail\dbgprint.hpp" />
<ClInclude Include="include\c4\yml\detail\print.hpp" />
<ClInclude Include="include\c4\yml\detail\stack.hpp" />
<ClInclude Include="include\c4\yml\emit.def.hpp" />

View File

@ -129,24 +129,6 @@ Tree parse_json_in_arena(csubstr filename, csubstr json
Tree parse_json_in_arena( csubstr json ) { Parser::handler_type event_handler; Parser parser(&event_handler); Tree tree(parser.callbacks()); substr src = tree.copy_to_arena(json); parse_json_in_place(&parser, {} , src, &tree, tree.root_id()); return tree; }
RYML_EXPORT C4_NO_INLINE size_t _find_last_newline_and_larger_indentation(csubstr s, size_t indentation) noexcept
{
if(indentation + 1 > s.len)
return npos;
for(size_t i = s.len-indentation-1; i != size_t(-1); --i)
{
if(s.str[i] == '\n')
{
csubstr rem = s.sub(i + 1);
size_t first = rem.first_not_of(' ');
first = (first != npos) ? first : rem.len;
if(first > indentation)
return i;
}
}
return npos;
}
//-----------------------------------------------------------------------------
RYML_EXPORT id_type estimate_tree_capacity(csubstr src)

View File

@ -1,5 +1,5 @@
#include "c4/yml/preprocess.hpp"
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */

View File

@ -1,6 +1,6 @@
#include "c4/yml/reference_resolver.hpp"
#include "c4/yml/common.hpp"
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#ifdef RYML_DBG
#include "c4/yml/detail/print.hpp"
#else
@ -31,7 +31,7 @@ void ReferenceResolver::gather_anchors_and_refs__(id_type n)
// insert key refs BEFORE inserting val refs
if(m_tree->has_key(n))
{
if(m_tree->key(n) == "<<")
if(!m_tree->is_key_quoted(n) && m_tree->key(n) == "<<")
{
_c4dbgpf("node[{}]: key is <<", n);
if(m_tree->has_val(n))
@ -264,7 +264,7 @@ void ReferenceResolver::resolve_()
_RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
{
_c4dbgpf("instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->val_anchor(refdata.target));
_c4dbgpf("instance[{}:node{}] target.anchor==key.anchor=={}", i, refdata.node, m_tree->key_anchor(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
_RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
// keys cannot be containers, so don't inherit container flags

View File

@ -1,6 +1,5 @@
#include "c4/yml/tag.hpp"
#include "c4/yml/tree.hpp"
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
namespace c4 {
@ -222,25 +221,7 @@ bool TagDirective::create_from_str(csubstr directive_)
return true;
}
bool TagDirective::create_from_str(csubstr directive_, Tree *tree)
{
_RYML_CB_CHECK(tree->callbacks(), directive_.begins_with("%TAG "));
if(!create_from_str(directive_))
{
_RYML_CB_ERR(tree->callbacks(), "invalid tag directive");
}
next_node_id = tree->size();
if(!tree->empty())
{
const id_type prev = tree->size() - 1;
if(tree->is_root(prev) && tree->type(prev) != NOTYPE && !tree->is_stream(prev))
++next_node_id;
}
_c4dbgpf("%TAG: handle={} prefix={} next_node={}", handle, prefix, next_node_id);
return true;
}
size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& callbacks) const
size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& callbacks, bool with_brackets) const
{
_c4dbgpf("%TAG: handle={} prefix={} next_node={}. tag={}", handle, prefix, next_node_id, tag);
_RYML_CB_ASSERT(callbacks, tag.len >= handle.len);
@ -258,16 +239,26 @@ size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& call
return 0; // return 0 to signal that the tag is local and cannot be resolved
}
}
size_t len = 1u + prefix.len + rest.len + 1u;
size_t len = prefix.len + rest.len;
if(with_brackets)
len += 2;
size_t numpc = rest.count('%');
if(numpc == 0)
{
if(len <= output.len)
{
output.str[0] = '<';
memcpy(1u + output.str, prefix.str, prefix.len);
memcpy(1u + output.str + prefix.len, rest.str, rest.len);
output.str[1u + prefix.len + rest.len] = '>';
if(with_brackets)
{
output.str[0] = '<';
memcpy(1u + output.str, prefix.str, prefix.len);
memcpy(1u + output.str + prefix.len, rest.str, rest.len);
output.str[1u + prefix.len + rest.len] = '>';
}
else
{
memcpy(output.str, prefix.str, prefix.len);
memcpy(output.str + prefix.len, rest.str, rest.len);
}
}
}
else
@ -290,7 +281,8 @@ size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& call
size_t prev = 0, wpos = 0;
auto appendstr = [&](csubstr s) { memcpy(output.str + wpos, s.str, s.len); wpos += s.len; };
auto appendchar = [&](char c) { output.str[wpos++] = c; };
appendchar('<');
if(with_brackets)
appendchar('<');
appendstr(prefix);
pos = rest.find('%');
_RYML_CB_ASSERT(callbacks, pos != npos);
@ -312,7 +304,8 @@ size_t TagDirective::transform(csubstr tag, substr output, Callbacks const& call
_RYML_CB_ASSERT(callbacks, prev > 0);
_RYML_CB_ASSERT(callbacks, rest.len >= prev);
appendstr(rest.sub(prev));
appendchar('>');
if(with_brackets)
appendchar('>');
_RYML_CB_ASSERT(callbacks, wpos == len);
}
}

View File

@ -1,5 +1,5 @@
#include "c4/yml/tree.hpp"
#include "c4/yml/detail/parser_dbg.hpp"
#include "c4/yml/detail/dbgprint.hpp"
#include "c4/yml/node.hpp"
#include "c4/yml/reference_resolver.hpp"
@ -857,7 +857,13 @@ void Tree::set_root_as_stream()
void Tree::remove_children(id_type node)
{
_RYML_CB_ASSERT(m_callbacks, get(node) != nullptr);
#if __GNUC__ >= 6
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
#endif
id_type ich = get(node)->m_first_child;
#if __GNUC__ >= 6
C4_SUPPRESS_WARNING_GCC_POP
#endif
while(ich != NONE)
{
remove_children(ich);
@ -1178,7 +1184,6 @@ id_type Tree::child_pos(id_type node, id_type ch) const
#if defined(__clang__)
# pragma clang diagnostic push
# pragma GCC diagnostic ignored "-Wnull-dereference"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# if __GNUC__ >= 6
@ -1336,6 +1341,37 @@ void Tree::to_stream(id_type node, type_bits more_flags)
}
//-----------------------------------------------------------------------------
void Tree::clear_style(id_type node, bool recurse)
{
NodeData *C4_RESTRICT d = _p(node);
d->m_type.clear_style();
if(!recurse)
return;
for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
clear_style(child, recurse);
}
void Tree::set_style_conditionally(id_type node,
NodeType type_mask,
NodeType rem_style_flags,
NodeType add_style_flags,
bool recurse)
{
NodeData *C4_RESTRICT d = _p(node);
if((d->m_type & type_mask) == type_mask)
{
d->m_type &= ~(NodeType)rem_style_flags;
d->m_type |= (NodeType)add_style_flags;
}
if(!recurse)
return;
for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
}
//-----------------------------------------------------------------------------
id_type Tree::num_tag_directives() const
{
@ -1366,10 +1402,30 @@ id_type Tree::add_tag_directive(TagDirective const& td)
return pos;
}
namespace {
bool _create_tag_directive_from_str(csubstr directive_, TagDirective *td, Tree *tree)
{
_RYML_CB_CHECK(tree->callbacks(), directive_.begins_with("%TAG "));
if(!td->create_from_str(directive_))
{
_RYML_CB_ERR(tree->callbacks(), "invalid tag directive");
}
td->next_node_id = tree->size();
if(!tree->empty())
{
const id_type prev = tree->size() - 1;
if(tree->is_root(prev) && tree->type(prev) != NOTYPE && !tree->is_stream(prev))
++td->next_node_id;
}
_c4dbgpf("%TAG: handle={} prefix={} next_node={}", td->handle, td->prefix, td->next_node_id);
return true;
}
} // namespace
bool Tree::add_tag_directive(csubstr directive_)
{
TagDirective td;
if(td.create_from_str(directive_, this))
if(_create_tag_directive_from_str(directive_, &td, this))
{
add_tag_directive(td);
return true;
@ -1802,5 +1858,121 @@ Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token
} // namespace c4
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include "c4/yml/event_handler_tree.hpp"
#include "c4/yml/parse_engine.def.hpp"
#include "c4/yml/parse.hpp"
namespace c4 {
namespace yml {
Location Tree::location(Parser const& parser, id_type node) const
{
// try hard to avoid getting the location from a null string.
Location loc;
if(_location_from_node(parser, node, &loc, 0))
return loc;
return parser.val_location(parser.source().str);
}
bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
{
if(has_key(node))
{
csubstr k = key(node);
if(C4_LIKELY(k.str != nullptr))
{
_RYML_CB_ASSERT(m_callbacks, k.is_sub(parser.source()));
_RYML_CB_ASSERT(m_callbacks, parser.source().is_super(k));
*loc = parser.val_location(k.str);
return true;
}
}
if(has_val(node))
{
csubstr v = val(node);
if(C4_LIKELY(v.str != nullptr))
{
_RYML_CB_ASSERT(m_callbacks, v.is_sub(parser.source()));
_RYML_CB_ASSERT(m_callbacks, parser.source().is_super(v));
*loc = parser.val_location(v.str);
return true;
}
}
if(is_container(node))
{
if(_location_from_cont(parser, node, loc))
return true;
}
if(type(node) != NOTYPE && level == 0)
{
// try the prev sibling
{
const id_type prev = prev_sibling(node);
if(prev != NONE)
{
if(_location_from_node(parser, prev, loc, level+1))
return true;
}
}
// try the next sibling
{
const id_type next = next_sibling(node);
if(next != NONE)
{
if(_location_from_node(parser, next, loc, level+1))
return true;
}
}
// try the parent
{
const id_type parent = this->parent(node);
if(parent != NONE)
{
if(_location_from_node(parser, parent, loc, level+1))
return true;
}
}
}
return false;
}
bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
{
_RYML_CB_ASSERT(m_callbacks, is_container(node));
if(!is_stream(node))
{
const char *node_start = _p(node)->m_val.scalar.str; // this was stored in the container
if(has_children(node))
{
id_type child = first_child(node);
if(has_key(child))
{
// when a map starts, the container was set after the key
csubstr k = key(child);
if(k.str && node_start > k.str)
node_start = k.str;
}
}
*loc = parser.val_location(node_start);
return true;
}
else // it's a stream
{
*loc = parser.val_location(parser.source().str); // just return the front of the buffer
}
return true;
}
} // namespace yml
} // namespace c4
C4_SUPPRESS_WARNING_GCC_CLANG_POP
C4_SUPPRESS_WARNING_MSVC_POP