1 #ifndef _C4_YML_EVENT_HANDLER_YAMLSTD_HPP_
2 #define _C4_YML_EVENT_HANDLER_YAMLSTD_HPP_
4 #ifdef RYML_SINGLE_HEADER
5 #include <ryml_all.hpp>
7 #ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
10 #ifndef _C4_YML_DETAIL_PRINT_HPP_
11 #include "c4/yml/detail/print.hpp"
15 #ifndef _C4_YML_EXTRA_STRING_HPP_
16 #include "./string.hpp"
19 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
20 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wold-style-cast")
21 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
66 extra::string_vector m_val_buffers;
67 extra::string m_key_tag_buf;
68 extra::string m_val_tag_buf;
70 bool m_has_yaml_directive;
71 extra::string m_arena;
75 #define _enable_(bits) _enable__<bits>()
76 #define _disable_(bits) _disable__<bits>()
77 #define _has_any_(bits) _has_any__<bits>()
97 m_has_yaml_directive =
false;
100 m_val_buffers.clear();
101 m_val_buffers.resize((
size_t)m_stack.size());
103 m_arena.reserve(1024);
104 m_key_tag_buf.resize(256);
105 m_val_tag_buf.resize(256);
118 this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
123 if((_num_tag_directives() || m_has_yaml_directive) && !m_has_docs)
124 _RYML_CB_ERR_(m_stack.m_callbacks,
"directives cannot be used without a document", {});
125 this->_stack_finish_parse();
130 while(m_stack.size() > 1)
163 _c4dbgp(
"begin_doc");
164 if(_stack_should_push_on_begin_doc())
178 if(_stack_should_pop_on_end_doc())
188 _c4dbgp(
"begin_doc_expl");
189 if(_stack_should_push_on_begin_doc())
194 _send_(
"+DOC ---\n");
201 _c4dbgp(
"end_doc_expl");
202 _send_(
"-DOC ...\n");
203 if(_stack_should_pop_on_end_doc())
208 m_has_yaml_directive =
false;
224 _mark_parent_with_children_();
234 _mark_parent_with_children_();
245 _mark_parent_with_children_();
255 _mark_parent_with_children_();
279 _mark_parent_with_children_();
289 _mark_parent_with_children_();
300 _mark_parent_with_children_();
310 _mark_parent_with_children_();
330 _RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
331 _buf_flush_to_(m_curr->level, m_parent->level);
332 m_curr->ev_data = {};
344 _buf_ensure_(tmp +
id_type(2));
346 _buf_flush_to_(m_curr->level, tmp);
350 begin_map_val_flow();
351 _RYML_CB_ASSERT(m_stack.m_callbacks, tmp != m_curr->level);
353 _buf_flush_to_(tmp, m_curr->level);
365 substr full = sink;(void)full;
367 _RYML_CB_ASSERT(m_stack.m_callbacks, full.len);
368 _RYML_CB_ASSERT(m_stack.m_callbacks, !full.count(
'\r'));
369 size_t docpos = sink.find_last(
"+DOC\n");
372 _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
373 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 5u < full.len);
374 sink.insert(
"+MAP\n", docpos + 5u);
379 docpos = sink.find_last(
"+DOC ---\n");
380 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos !=
npos);
381 _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
382 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 9u < full.len);
383 sink.insert(
"+MAP\n", docpos + 9u);
398 _c4dbgpf(
"node[{}]: set key scalar plain as empty", m_curr->node_id);
399 _send_key_scalar_({},
':');
404 _c4dbgpf(
"node[{}]: set val scalar plain as empty", m_curr->node_id);
405 _send_val_scalar_({},
':');
411 _c4dbgpf(
"node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
412 _send_key_scalar_(scalar,
':');
417 _c4dbgpf(
"node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
418 _send_val_scalar_(scalar,
':');
425 _c4dbgpf(
"node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
426 _send_key_scalar_(scalar,
'"');
431 _c4dbgpf(
"node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
432 _send_val_scalar_(scalar,
'"');
439 _c4dbgpf(
"node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
440 _send_key_scalar_(scalar,
'\'');
445 _c4dbgpf(
"node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
446 _send_val_scalar_(scalar,
'\'');
453 _c4dbgpf(
"node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
454 _send_key_scalar_(scalar,
'|');
459 _c4dbgpf(
"node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
460 _send_val_scalar_(scalar,
'|');
467 _c4dbgpf(
"node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
468 _send_key_scalar_(scalar,
'>');
473 _c4dbgpf(
"node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
474 _send_val_scalar_(scalar,
'>');
481 C4_NOT_IMPLEMENTED();
485 C4_NOT_IMPLEMENTED();
497 _c4dbgpf(
"node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
499 _RYML_CB_ERR_(m_stack.m_callbacks,
"key cannot have both anchor and ref", m_curr->pos);
500 _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with(
'&'));
502 m_curr->ev_data.m_key.anchor = anchor;
506 _c4dbgpf(
"node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
508 _RYML_CB_ERR_(m_stack.m_callbacks,
"val cannot have both anchor and ref", m_curr->pos);
509 _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with(
'&'));
511 m_curr->ev_data.m_val.anchor = anchor;
516 _c4dbgpf(
"node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
518 _RYML_CB_ERR_(m_stack.m_callbacks,
"key cannot have both anchor and ref", m_curr->pos);
519 _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with(
'*'));
527 _c4dbgpf(
"node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
529 _RYML_CB_ERR_(m_stack.m_callbacks,
"val cannot have both anchor and ref", m_curr->pos);
530 _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with(
'*'));
546 _c4dbgpf(
"node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
548 m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
552 _c4dbgpf(
"node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
554 m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
566 _RYML_CB_ASSERT(m_stack.m_callbacks, directive.begins_with(
'%'));
567 if(directive.begins_with(
"%TAG"))
569 const id_type pos = _num_tag_directives();
571 _RYML_CB_ERR_(m_stack.m_callbacks,
"too many directives", m_curr->pos);
572 if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
573 _RYML_CB_ERR_(m_stack.m_callbacks,
"failed to add directive", m_curr->pos);
575 else if(directive.begins_with(
"%YAML"))
577 _c4dbgpf(
"%YAML directive! ignoring...: {}", directive);
578 if(C4_UNLIKELY(m_has_yaml_directive))
579 _RYML_CB_ERR_(m_stack.m_callbacks,
"multiple yaml directives", m_curr->pos);
580 m_has_yaml_directive =
true;
584 _c4dbgpf(
"unknown directive! ignoring... {}", directive);
597 const size_t sz = m_arena.size();
598 csubstr prev = m_arena;
599 m_arena.resize(sz + len);
602 if(curr.str != prev.str)
603 _stack_relocate_to_new_arena(prev, curr);
609 csubstr prev = m_arena;
610 if(!prev.is_super(*relocated))
611 return alloc_arena(len);
612 substr out = alloc_arena(len);
614 if(curr.str != prev.str)
615 *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
630 _buf_ensure_(m_stack.size() +
id_type(1));
632 m_curr->ev_data = {};
633 _c4dbgpf(
"pushed! level={}", m_curr->level);
639 _buf_flush_to_(m_curr->level, m_parent->level);
643 template<type_bits bits> C4_ALWAYS_INLINE
void _enable__() noexcept
645 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
647 template<type_bits bits> C4_ALWAYS_INLINE
void _disable__() noexcept
649 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
651 template<type_bits bits> C4_ALWAYS_INLINE
bool _has_any__() const noexcept
653 return (m_curr->ev_data.m_type.type & bits) != 0;
656 void _mark_parent_with_children_()
659 m_parent->has_children =
true;
662 EventSink& _buf_() noexcept
664 _RYML_CB_ASSERT(m_stack.m_callbacks, m_curr->level < m_val_buffers.size());
665 return m_val_buffers[m_curr->level];
668 EventSink& _buf_(
id_type level) noexcept
670 _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
671 return m_val_buffers[level];
674 EventSink
const& _buf_(
id_type level)
const noexcept
676 _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.size());
677 return m_val_buffers[level];
680 static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
686 void _buf_flush_to_(
id_type level_src,
id_type level_dst) noexcept
688 auto &src = _buf_(level_src);
689 auto &dst = _buf_(level_dst);
690 _buf_flush_to_(src, dst);
693 void _buf_flush_() noexcept
695 _buf_flush_to_(_buf_(), *m_sink);
698 void _buf_ensure_(
id_type size_needed) noexcept
700 if(size_needed > m_val_buffers.size())
701 m_val_buffers.resize(size_needed);
704 C4_ALWAYS_INLINE
void _send_(csubstr s) noexcept { _buf_().append(s); }
705 C4_ALWAYS_INLINE
void _send_(
char c) noexcept { _buf_().append(c); }
707 void _send_key_scalar_(csubstr scalar,
char scalar_type_code)
712 _send_(scalar_type_code);
716 void _send_val_scalar_(csubstr scalar,
char scalar_type_code)
721 _send_(scalar_type_code);
726 void _send_key_props_()
731 _send_(m_curr->ev_data.m_key.anchor);
735 _send_tag_(m_curr->ev_data.m_key.tag);
737 m_curr->ev_data.m_key = {};
740 void _send_val_props_()
745 _send_(m_curr->ev_data.m_val.anchor);
747 if(m_curr->ev_data.m_type.type &
VALTAG)
749 _send_tag_(m_curr->ev_data.m_val.tag);
751 m_curr->ev_data.m_val = {};
754 void _send_tag_(csubstr tag)
756 _RYML_CB_ASSERT(m_stack.m_callbacks, !tag.empty());
757 if(tag.str[0] ==
'<')
770 void _clear_tag_directives_()
772 for(TagDirective &td : m_tag_directives)
775 id_type _num_tag_directives()
const
779 if(m_tag_directives[i].handle.empty())
783 csubstr _transform_directive(csubstr tag, extra::string *output)
790 TagDirective
const& td = m_tag_directives[i];
791 if(td.handle.empty())
793 if(tag.begins_with(td.handle))
797 size_t len = td.
transform(tag, *output, m_stack.m_callbacks);
800 if(tag.begins_with(
"!<"))
804 if(len > output->size())
806 _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
809 output->resize(output->capacity());
812 return csubstr(*output).first(len);
815 if(tag.begins_with(
'!'))
819 _RYML_CB_ERR_(m_stack.m_callbacks,
"tag not found", m_curr->pos);
827 _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
829 output->resize(result.len);
830 output->resize(output->capacity());
848 C4_SUPPRESS_WARNING_GCC_POP
Callbacks const & get_callbacks()
get the global callbacks
void append_escaped(extra::string *s, csubstr val)
NodeType_e
a bit mask for marking node types and styles
@ VALANCH
the val has an &anchor
@ KEY_DQUO
mark key scalar as double quoted "
@ VALREF
a *reference: the val references an &anchor
@ VALNIL
the val is null (eg {a : } results in a null val)
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
@ VAL_FOLDED
mark val scalar as multiline, block folded >
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ KEYTAG
the key has a tag
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ VALTAG
the val has a tag
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
@ VAL_SQUO
mark val scalar as single quoted '
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ KEYREF
a *reference: the key references an &anchor
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
@ KEYANCH
the key has an &anchor
@ VAL_DQUO
mark val scalar as double quoted "
@ KEY_SQUO
mark key scalar as single quoted '
@ VAL_LITERAL
mark val scalar as multiline, block literal |
@ KEY_LITERAL
mark key scalar as multiline, block literal |
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
@ KEY_FOLDED
mark key scalar as multiline, block folded >
@ KEYNIL
the key is null (eg { : b} results in a null key)
substr to_substr(substr s) noexcept
neutral version for use in generic code
bool is_custom_tag(csubstr tag)
csubstr normalize_tag_long(csubstr tag)
#define RYML_MAX_TAG_DIRECTIVES
the maximum number of tag directives in a Tree
void(*)(void *, csubstr prev_arena, substr next_arena) pfn_relocate_arena
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
@ npos
a null string position
@ RTOP
reading at top level
@ RUNK
reading unknown state (when starting): must determine whether scalar, map or seq
a c-style callbacks class.
Use this class a base of implementations of event handler to simplify the stack logic.
The stack state needed specifically by EventHandlerYamlStd.
The event handler producing standard YAML events as used in the YAML test suite.
void actually_val_is_first_key_of_new_map_flow()
set the previous val as the first key of a new map, with flow style.
substr alloc_arena(size_t len, substr *relocated)
void begin_map_val_block()
void set_key_scalar_plain(csubstr scalar)
void begin_doc()
implicit doc start (without —)
EventHandlerYamlStd(EventSink *sink, Callbacks const &cb)
void begin_seq_key_flow()
void set_key_anchor(csubstr anchor)
void set_key_scalar_plain_empty() noexcept
void end_doc()
implicit doc end (without ...)
void begin_seq_key_block()
void set_key_scalar_folded(csubstr scalar)
void set_key_scalar_dquoted(csubstr scalar)
void set_val_scalar_plain_empty() noexcept
void add_directive(csubstr directive)
void set_val_scalar_literal(csubstr scalar)
void set_val_ref(csubstr ref)
void begin_doc_expl()
explicit doc start, with —
void mark_key_scalar_unfiltered()
void set_key_scalar_literal(csubstr scalar)
void set_val_scalar_folded(csubstr scalar)
substr alloc_arena(size_t len)
void end_doc_expl()
explicit doc end, with ...
void set_val_scalar_plain(csubstr scalar)
void start_parse(const char *filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
EventHandlerYamlStd(Callbacks const &cb)
void begin_map_val_flow()
void set_key_ref(csubstr ref)
void set_val_scalar_dquoted(csubstr scalar)
void mark_val_scalar_unfiltered()
void begin_seq_val_flow()
void set_key_scalar_squoted(csubstr scalar)
void set_key_tag(csubstr tag)
void set_val_tag(csubstr tag)
void set_val_anchor(csubstr anchor)
void begin_map_key_flow()
void actually_val_is_first_key_of_new_map_block()
like its flow counterpart, but this function can only be called after the end of a flow-val at root o...
void set_val_scalar_squoted(csubstr scalar)
void begin_map_key_block()
void begin_seq_val_block()
EventHandlerYamlStd(EventSink *sink)
contains the data for each YAML node.
size_t transform(csubstr tag, substr output, Callbacks const &callbacks) const