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;
72 #define _enable_(bits) _enable__<bits>()
73 #define _disable_(bits) _disable__<bits>()
74 #define _has_any_(bits) _has_any__<bits>()
76 void _dbg_print()
const
80 for(
id_type level = 0; level < n; ++level)
85 for(
id_type i = 0; i < m_stack.size(); ++i)
87 csubstr
const& str = _buf_(i);
89 _dbg_printf(
"[{}]\n", i);
90 for(csubstr ln : str.split(
'\n'))
93 _dbg_printf(
"{}\n", ln);
107 EventHandlerTestSuite(
EventSink *sink,
Callbacks const& cb) :
EventHandlerStack(cb), m_sink(sink), m_val_buffers(), m_key_tag_buf(), m_val_tag_buf(), m_tag_directives(), m_has_yaml_directive(), m_arena(), m_has_docs(), m_src()
117 m_has_yaml_directive =
false;
120 m_val_buffers.
clear();
121 m_val_buffers.
resize((
size_t)m_stack.size());
124 m_key_tag_buf.
resize(256);
125 m_val_tag_buf.
resize(256);
139 this->_stack_start_parse(filename, src, relocate_arena, relocate_arena_data);
144 if((_num_tag_directives() || m_has_yaml_directive) && !m_has_docs)
145 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"directives cannot be used without a document");
146 this->_stack_finish_parse();
151 while(m_stack.size() > 1)
184 _c4dbgp(
"begin_doc");
185 if(_stack_should_push_on_begin_doc())
199 if(_stack_should_pop_on_end_doc())
209 _c4dbgp(
"begin_doc_expl");
210 if(_stack_should_push_on_begin_doc())
215 _send_(
"+DOC ---\n");
222 _c4dbgp(
"end_doc_expl");
223 _send_(
"-DOC ...\n");
224 if(_stack_should_pop_on_end_doc())
229 m_has_yaml_directive =
false;
241 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
245 _mark_parent_with_children_();
251 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
255 _mark_parent_with_children_();
262 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
266 _mark_parent_with_children_();
272 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
276 _mark_parent_with_children_();
302 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
306 _mark_parent_with_children_();
312 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
316 _mark_parent_with_children_();
323 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
327 _mark_parent_with_children_();
333 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
337 _mark_parent_with_children_();
363 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
364 _buf_flush_to_(m_curr->level, m_parent->level);
365 m_curr->ev_data = {};
375 _c4dbgpf(
"node[{}]: actually_val_is_first_key_of_new_map_flow", m_curr->node_id);
378 _buf_ensure_(tmp +
id_type(2));
380 _buf_flush_to_(m_curr->level, tmp);
384 begin_map_val_flow();
385 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, tmp != m_curr->level);
387 _buf_flush_to_(tmp, m_curr->level);
398 _c4dbgpf(
"node[{}]: actually_val_is_first_key_of_new_map_block", m_curr->node_id);
400 csubstr full = sink;(void)full;
402 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, full.len);
403 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !full.count(
'\r'));
404 size_t docpos = sink.
find_last(
"+DOC\n");
407 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
408 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, docpos + 5u < full.len);
409 sink.
insert(
"+MAP\n", docpos + 5u);
417 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
418 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, docpos + 9u < full.len);
419 sink.
insert(
"+MAP\n", docpos + 9u);
423 sink.
insert(
"+MAP\n", 0u);
439 _c4dbgpf(
"node[{}]: set key scalar plain as empty", m_curr->node_id);
440 _send_key_scalar_({},
':');
445 _c4dbgpf(
"node[{}]: set val scalar plain as empty", m_curr->node_id);
446 _send_val_scalar_({},
':');
452 _c4dbgpf(
"node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
453 _send_key_scalar_(scalar,
':');
458 _c4dbgpf(
"node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
459 _send_val_scalar_(scalar,
':');
466 _c4dbgpf(
"node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
467 _send_key_scalar_(scalar,
'"');
472 _c4dbgpf(
"node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
473 _send_val_scalar_(scalar,
'"');
480 _c4dbgpf(
"node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
481 _send_key_scalar_(scalar,
'\'');
486 _c4dbgpf(
"node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
487 _send_val_scalar_(scalar,
'\'');
494 _c4dbgpf(
"node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
495 _send_key_scalar_(scalar,
'|');
500 _c4dbgpf(
"node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
501 _send_val_scalar_(scalar,
'|');
508 _c4dbgpf(
"node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
509 _send_key_scalar_(scalar,
'>');
514 _c4dbgpf(
"node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
515 _send_val_scalar_(scalar,
'>');
538 _c4dbgpf(
"node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
540 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !anchor.begins_with(
'&'));
542 m_curr->ev_data.m_key.anchor = anchor;
546 _c4dbgpf(
"node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
548 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !anchor.begins_with(
'&'));
550 m_curr->ev_data.m_val.anchor = anchor;
555 _c4dbgpf(
"node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
557 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"key cannot have both anchor and ref");
558 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, ref.begins_with(
'*'));
566 _c4dbgpf(
"node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
568 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"val cannot have both anchor and ref");
569 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, ref.begins_with(
'*'));
585 _c4dbgpf(
"node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
587 m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
591 _c4dbgpf(
"node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
593 m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
605 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, directive.begins_with(
'%'));
606 if(directive.begins_with(
"%TAG"))
608 const id_type pos = _num_tag_directives();
610 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"too many directives");
611 if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
612 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"failed to add directive");
614 else if(directive.begins_with(
"%YAML"))
616 _c4dbgpf(
"%YAML directive! ignoring...: {}", directive);
617 if(C4_UNLIKELY(m_has_yaml_directive))
618 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"multiple yaml directives");
619 m_has_yaml_directive =
true;
623 _c4dbgpf(
"unknown directive! ignoring... {}", directive);
636 const size_t sz = m_arena.
size();
637 csubstr prev = m_arena;
641 if(curr.str != prev.str)
642 _stack_relocate_to_new_arena(prev, curr);
648 csubstr prev = m_arena;
649 if(!prev.is_super(*relocated))
650 return alloc_arena(len);
651 substr out = alloc_arena(len);
653 if(curr.str != prev.str)
654 *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
669 _buf_ensure_(m_stack.size() +
id_type(1));
671 m_curr->ev_data = {};
672 _c4dbgpf(
"pushed! level={}", m_curr->level);
678 _buf_flush_to_(m_curr->level, m_parent->level);
682 template<type_bits bits> C4_ALWAYS_INLINE
void _enable__() noexcept
684 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
686 template<type_bits bits> C4_ALWAYS_INLINE
void _disable__() noexcept
688 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
690 template<type_bits bits> C4_ALWAYS_INLINE
bool _has_any__() const noexcept
692 return (m_curr->ev_data.m_type.type & bits) != 0;
695 void _mark_parent_with_children_()
698 m_parent->has_children =
true;
701 EventSink& _buf_() noexcept
703 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_curr->level < m_val_buffers.
size());
704 return m_val_buffers[m_curr->level];
707 EventSink& _buf_(
id_type level) noexcept
709 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, level < m_val_buffers.
size());
710 return m_val_buffers[level];
713 EventSink
const& _buf_(
id_type level)
const noexcept
715 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, level < m_val_buffers.
size());
716 return m_val_buffers[level];
719 static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
725 void _buf_flush_to_(
id_type level_src,
id_type level_dst) noexcept
727 auto &src = _buf_(level_src);
728 auto &dst = _buf_(level_dst);
729 _buf_flush_to_(src, dst);
732 void _buf_flush_() noexcept
734 _buf_flush_to_(_buf_(), *m_sink);
737 void _buf_ensure_(
id_type size_needed) noexcept
739 if(size_needed > m_val_buffers.
size())
740 m_val_buffers.
resize(size_needed);
743 C4_ALWAYS_INLINE
void _send_(csubstr s) noexcept { _buf_().append(s); }
744 C4_ALWAYS_INLINE
void _send_(
char c) noexcept { _buf_().append(c); }
746 void _send_key_scalar_(csubstr scalar,
char scalar_type_code)
751 _send_(scalar_type_code);
755 void _send_val_scalar_(csubstr scalar,
char scalar_type_code)
760 _send_(scalar_type_code);
765 void _send_key_props_()
770 _send_(m_curr->ev_data.m_key.anchor);
774 _send_tag_(m_curr->ev_data.m_key.tag);
776 m_curr->ev_data.m_key = {};
779 void _send_val_props_()
784 _send_(m_curr->ev_data.m_val.anchor);
786 if(m_curr->ev_data.m_type.type &
VALTAG)
788 _send_tag_(m_curr->ev_data.m_val.tag);
790 m_curr->ev_data.m_val = {};
793 void _send_tag_(csubstr tag)
795 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !tag.empty());
796 if(tag.str[0] ==
'<')
809 void _clear_tag_directives_()
811 for(TagDirective &td : m_tag_directives)
814 id_type _num_tag_directives()
const
818 if(m_tag_directives[i].handle.empty())
822 csubstr _transform_directive(csubstr tag, extra::string *output)
829 TagDirective
const& td = m_tag_directives[i];
830 if(td.handle.empty())
832 if(tag.begins_with(td.handle))
836 size_t len = td.
transform(tag, *output, m_stack.m_callbacks);
839 if(tag.begins_with(
"!<"))
843 if(len > output->size())
845 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !retry);
848 output->resize(output->capacity());
851 return csubstr(*output).first(len);
854 if(tag.begins_with(
'!'))
858 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"tag not found");
866 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !retry);
868 output->resize(result.len);
869 output->resize(output->capacity());
888 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
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
A c-style callbacks class to customize behavior on errors or allocation.
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 start_parse(const char *filename, csubstr src, detail::pfn_relocate_arena relocate_arena, void *relocate_arena_data)
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 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)