1 #ifndef _C4_YML_EXTRA_EVENT_HANDLER_TESTSUITE_HPP_
2 #define _C4_YML_EXTRA_EVENT_HANDLER_TESTSUITE_HPP_
4 #ifndef RYML_SINGLE_HEADER
5 #ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
9 #ifndef _C4_YML_EXTRA_STRING_HPP_
13 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
14 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wold-style-cast")
15 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
28 struct EventHandlerTestSuiteState :
public ParserState
52 using state = EventHandlerTestSuiteState;
66 bool m_has_yaml_directive;
71 #define _enable_(bits) _enable__<bits>()
72 #define _disable_(bits) _disable__<bits>()
73 #define _has_any_(bits) _has_any__<bits>()
93 m_has_yaml_directive =
false;
96 m_val_buffers.
clear();
97 m_val_buffers.
resize((
size_t)m_stack.size());
100 m_key_tag_buf.
resize(256);
101 m_val_tag_buf.
resize(256);
114 this->_stack_start_parse(filename, relocate_arena, relocate_arena_data);
119 if((_num_tag_directives() || m_has_yaml_directive) && !m_has_docs)
120 _RYML_CB_ERR_(m_stack.m_callbacks,
"directives cannot be used without a document", {});
121 this->_stack_finish_parse();
126 while(m_stack.size() > 1)
159 _c4dbgp(
"begin_doc");
160 if(_stack_should_push_on_begin_doc())
174 if(_stack_should_pop_on_end_doc())
184 _c4dbgp(
"begin_doc_expl");
185 if(_stack_should_push_on_begin_doc())
190 _send_(
"+DOC ---\n");
197 _c4dbgp(
"end_doc_expl");
198 _send_(
"-DOC ...\n");
199 if(_stack_should_pop_on_end_doc())
204 m_has_yaml_directive =
false;
220 _mark_parent_with_children_();
230 _mark_parent_with_children_();
241 _mark_parent_with_children_();
251 _mark_parent_with_children_();
275 _mark_parent_with_children_();
285 _mark_parent_with_children_();
296 _mark_parent_with_children_();
306 _mark_parent_with_children_();
326 _RYML_CB_ASSERT(m_stack.m_callbacks, m_parent);
327 _buf_flush_to_(m_curr->level, m_parent->level);
328 m_curr->ev_data = {};
340 _buf_ensure_(tmp +
id_type(2));
342 _buf_flush_to_(m_curr->level, tmp);
346 begin_map_val_flow();
347 _RYML_CB_ASSERT(m_stack.m_callbacks, tmp != m_curr->level);
349 _buf_flush_to_(tmp, m_curr->level);
361 substr full = sink;(void)full;
363 _RYML_CB_ASSERT(m_stack.m_callbacks, full.len);
364 _RYML_CB_ASSERT(m_stack.m_callbacks, !full.count(
'\r'));
365 size_t docpos = sink.
find_last(
"+DOC\n");
368 _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
369 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 5u < full.len);
370 sink.
insert(
"+MAP\n", docpos + 5u);
376 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos !=
npos);
377 _RYML_CB_ASSERT(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
378 _RYML_CB_ASSERT(m_stack.m_callbacks, docpos + 9u < full.len);
379 sink.
insert(
"+MAP\n", docpos + 9u);
394 _c4dbgpf(
"node[{}]: set key scalar plain as empty", m_curr->node_id);
395 _send_key_scalar_({},
':');
400 _c4dbgpf(
"node[{}]: set val scalar plain as empty", m_curr->node_id);
401 _send_val_scalar_({},
':');
407 _c4dbgpf(
"node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
408 _send_key_scalar_(scalar,
':');
413 _c4dbgpf(
"node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
414 _send_val_scalar_(scalar,
':');
421 _c4dbgpf(
"node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
422 _send_key_scalar_(scalar,
'"');
427 _c4dbgpf(
"node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
428 _send_val_scalar_(scalar,
'"');
435 _c4dbgpf(
"node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
436 _send_key_scalar_(scalar,
'\'');
441 _c4dbgpf(
"node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
442 _send_val_scalar_(scalar,
'\'');
449 _c4dbgpf(
"node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
450 _send_key_scalar_(scalar,
'|');
455 _c4dbgpf(
"node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
456 _send_val_scalar_(scalar,
'|');
463 _c4dbgpf(
"node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
464 _send_key_scalar_(scalar,
'>');
469 _c4dbgpf(
"node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
470 _send_val_scalar_(scalar,
'>');
493 _c4dbgpf(
"node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
495 _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with(
'&'));
497 m_curr->ev_data.m_key.anchor = anchor;
501 _c4dbgpf(
"node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
503 _RYML_CB_ASSERT(m_stack.m_callbacks, !anchor.begins_with(
'&'));
505 m_curr->ev_data.m_val.anchor = anchor;
510 _c4dbgpf(
"node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
512 _RYML_CB_ERR_(m_stack.m_callbacks,
"key cannot have both anchor and ref", m_curr->pos);
513 _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with(
'*'));
521 _c4dbgpf(
"node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
523 _RYML_CB_ERR_(m_stack.m_callbacks,
"val cannot have both anchor and ref", m_curr->pos);
524 _RYML_CB_ASSERT(m_stack.m_callbacks, ref.begins_with(
'*'));
540 _c4dbgpf(
"node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
542 m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
546 _c4dbgpf(
"node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
548 m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
560 _RYML_CB_ASSERT(m_stack.m_callbacks, directive.begins_with(
'%'));
561 if(directive.begins_with(
"%TAG"))
563 const id_type pos = _num_tag_directives();
565 _RYML_CB_ERR_(m_stack.m_callbacks,
"too many directives", m_curr->pos);
566 if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
567 _RYML_CB_ERR_(m_stack.m_callbacks,
"failed to add directive", m_curr->pos);
569 else if(directive.begins_with(
"%YAML"))
571 _c4dbgpf(
"%YAML directive! ignoring...: {}", directive);
572 if(C4_UNLIKELY(m_has_yaml_directive))
573 _RYML_CB_ERR_(m_stack.m_callbacks,
"multiple yaml directives", m_curr->pos);
574 m_has_yaml_directive =
true;
578 _c4dbgpf(
"unknown directive! ignoring... {}", directive);
591 const size_t sz = m_arena.
size();
592 csubstr prev = m_arena;
596 if(curr.str != prev.str)
597 _stack_relocate_to_new_arena(prev, curr);
603 csubstr prev = m_arena;
604 if(!prev.is_super(*relocated))
605 return alloc_arena(len);
606 substr out = alloc_arena(len);
608 if(curr.str != prev.str)
609 *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
624 _buf_ensure_(m_stack.size() +
id_type(1));
626 m_curr->ev_data = {};
627 _c4dbgpf(
"pushed! level={}", m_curr->level);
633 _buf_flush_to_(m_curr->level, m_parent->level);
637 template<type_bits bits> C4_ALWAYS_INLINE
void _enable__() noexcept
639 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
641 template<type_bits bits> C4_ALWAYS_INLINE
void _disable__() noexcept
643 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
645 template<type_bits bits> C4_ALWAYS_INLINE
bool _has_any__() const noexcept
647 return (m_curr->ev_data.m_type.type & bits) != 0;
650 void _mark_parent_with_children_()
653 m_parent->has_children =
true;
656 EventSink& _buf_() noexcept
658 _RYML_CB_ASSERT(m_stack.m_callbacks, m_curr->level < m_val_buffers.
size());
659 return m_val_buffers[m_curr->level];
662 EventSink& _buf_(
id_type level) noexcept
664 _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.
size());
665 return m_val_buffers[level];
668 EventSink
const& _buf_(
id_type level)
const noexcept
670 _RYML_CB_ASSERT(m_stack.m_callbacks, level < m_val_buffers.
size());
671 return m_val_buffers[level];
674 static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
680 void _buf_flush_to_(
id_type level_src,
id_type level_dst) noexcept
682 auto &src = _buf_(level_src);
683 auto &dst = _buf_(level_dst);
684 _buf_flush_to_(src, dst);
687 void _buf_flush_() noexcept
689 _buf_flush_to_(_buf_(), *m_sink);
692 void _buf_ensure_(
id_type size_needed) noexcept
694 if(size_needed > m_val_buffers.
size())
695 m_val_buffers.
resize(size_needed);
698 C4_ALWAYS_INLINE
void _send_(csubstr s) noexcept { _buf_().append(s); }
699 C4_ALWAYS_INLINE
void _send_(
char c) noexcept { _buf_().append(c); }
701 void _send_key_scalar_(csubstr scalar,
char scalar_type_code)
706 _send_(scalar_type_code);
710 void _send_val_scalar_(csubstr scalar,
char scalar_type_code)
715 _send_(scalar_type_code);
720 void _send_key_props_()
725 _send_(m_curr->ev_data.m_key.anchor);
729 _send_tag_(m_curr->ev_data.m_key.tag);
731 m_curr->ev_data.m_key = {};
734 void _send_val_props_()
739 _send_(m_curr->ev_data.m_val.anchor);
741 if(m_curr->ev_data.m_type.type &
VALTAG)
743 _send_tag_(m_curr->ev_data.m_val.tag);
745 m_curr->ev_data.m_val = {};
748 void _send_tag_(csubstr tag)
750 _RYML_CB_ASSERT(m_stack.m_callbacks, !tag.empty());
751 if(tag.str[0] ==
'<')
764 void _clear_tag_directives_()
766 for(TagDirective &td : m_tag_directives)
769 id_type _num_tag_directives()
const
773 if(m_tag_directives[i].handle.empty())
777 csubstr _transform_directive(csubstr tag, extra::string *output)
784 TagDirective
const& td = m_tag_directives[i];
785 if(td.handle.empty())
787 if(tag.begins_with(td.handle))
791 size_t len = td.
transform(tag, *output, m_stack.m_callbacks);
794 if(tag.begins_with(
"!<"))
798 if(len > output->size())
800 _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
803 output->resize(output->capacity());
806 return csubstr(*output).first(len);
809 if(tag.begins_with(
'!'))
813 _RYML_CB_ERR_(m_stack.m_callbacks,
"tag not found", m_curr->pos);
821 _RYML_CB_CHECK(m_stack.m_callbacks, !retry);
823 output->resize(result.len);
824 output->resize(output->capacity());
843 C4_SUPPRESS_WARNING_GCC_POP
Callbacks const & get_callbacks()
get the global callbacks
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.
size_t transform(csubstr tag, substr output, Callbacks const &callbacks, bool with_brackets=true) const
This event produces standard YAML events as used in the YAML test suite.
void add_directive(csubstr directive)
void set_key_scalar_plain_empty() noexcept
void begin_seq_val_block()
void set_val_ref(csubstr ref)
EventHandlerTestSuite(EventSink *sink, Callbacks const &cb)
void begin_seq_key_flow()
void set_key_anchor(csubstr anchor)
void set_val_tag(csubstr tag)
void set_key_tag(csubstr tag)
void set_key_scalar_folded(csubstr scalar)
void end_doc()
implicit doc end (without ...)
void set_key_ref(csubstr ref)
void set_key_scalar_plain(csubstr scalar)
void set_val_anchor(csubstr anchor)
void begin_seq_val_flow()
void begin_map_key_flow()
void set_key_scalar_squoted(csubstr scalar)
void set_val_scalar_dquoted(csubstr scalar)
void begin_doc_expl()
explicit doc start, with —
void begin_map_val_block()
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 set_val_scalar_folded(csubstr scalar)
void begin_map_key_block()
void mark_key_scalar_unfiltered()
void set_val_scalar_literal(csubstr scalar)
substr alloc_arena(size_t len)
void mark_val_scalar_unfiltered()
void set_key_scalar_literal(csubstr scalar)
EventHandlerTestSuite(EventSink *sink)
void set_val_scalar_plain(csubstr scalar)
void set_val_scalar_plain_empty() noexcept
void set_key_scalar_dquoted(csubstr scalar)
void set_val_scalar_squoted(csubstr scalar)
void begin_seq_key_block()
void start_parse(const char *filename, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
void begin_doc()
implicit doc start (without —)
void end_doc_expl()
explicit doc end, with ...
EventHandlerTestSuiteState state
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 begin_map_val_flow()
EventHandlerTestSuite(Callbacks const &cb)