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>()
84 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()
94 m_has_yaml_directive =
false;
97 m_val_buffers.
clear();
98 m_val_buffers.
resize((
size_t)m_stack.size());
101 m_key_tag_buf.
resize(256);
102 m_val_tag_buf.
resize(256);
116 this->_stack_start_parse(filename, src, relocate_arena, relocate_arena_data);
121 if((_num_tag_directives() || m_has_yaml_directive) && !m_has_docs)
122 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"directives cannot be used without a document");
123 this->_stack_finish_parse();
128 while(m_stack.size() > 1)
161 _c4dbgp(
"begin_doc");
162 if(_stack_should_push_on_begin_doc())
176 if(_stack_should_pop_on_end_doc())
186 _c4dbgp(
"begin_doc_expl");
187 if(_stack_should_push_on_begin_doc())
192 _send_(
"+DOC ---\n");
199 _c4dbgp(
"end_doc_expl");
200 _send_(
"-DOC ...\n");
201 if(_stack_should_pop_on_end_doc())
206 m_has_yaml_directive =
false;
218 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
222 _mark_parent_with_children_();
228 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
232 _mark_parent_with_children_();
239 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
243 _mark_parent_with_children_();
249 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
253 _mark_parent_with_children_();
279 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
283 _mark_parent_with_children_();
289 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
293 _mark_parent_with_children_();
300 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
304 _mark_parent_with_children_();
310 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !
_has_any_(
VAL));
314 _mark_parent_with_children_();
340 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
341 _buf_flush_to_(m_curr->level, m_parent->level);
342 m_curr->ev_data = {};
354 _buf_ensure_(tmp +
id_type(2));
356 _buf_flush_to_(m_curr->level, tmp);
360 begin_map_val_flow();
361 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, tmp != m_curr->level);
363 _buf_flush_to_(tmp, m_curr->level);
375 substr full = sink;(void)full;
377 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, full.len);
378 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !full.count(
'\r'));
379 size_t docpos = sink.
find_last(
"+DOC\n");
382 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
383 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, docpos + 5u < full.len);
384 sink.
insert(
"+MAP\n", docpos + 5u);
390 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, docpos !=
npos);
391 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, (m_stack.size() == 1u) ? (docpos >= 5u) : (docpos == 0u));
392 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, docpos + 9u < full.len);
393 sink.
insert(
"+MAP\n", docpos + 9u);
408 _c4dbgpf(
"node[{}]: set key scalar plain as empty", m_curr->node_id);
409 _send_key_scalar_({},
':');
414 _c4dbgpf(
"node[{}]: set val scalar plain as empty", m_curr->node_id);
415 _send_val_scalar_({},
':');
421 _c4dbgpf(
"node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
422 _send_key_scalar_(scalar,
':');
427 _c4dbgpf(
"node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
428 _send_val_scalar_(scalar,
':');
435 _c4dbgpf(
"node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
436 _send_key_scalar_(scalar,
'"');
441 _c4dbgpf(
"node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
442 _send_val_scalar_(scalar,
'"');
449 _c4dbgpf(
"node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
450 _send_key_scalar_(scalar,
'\'');
455 _c4dbgpf(
"node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
456 _send_val_scalar_(scalar,
'\'');
463 _c4dbgpf(
"node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
464 _send_key_scalar_(scalar,
'|');
469 _c4dbgpf(
"node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
470 _send_val_scalar_(scalar,
'|');
477 _c4dbgpf(
"node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
478 _send_key_scalar_(scalar,
'>');
483 _c4dbgpf(
"node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
484 _send_val_scalar_(scalar,
'>');
507 _c4dbgpf(
"node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
509 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !anchor.begins_with(
'&'));
511 m_curr->ev_data.m_key.anchor = anchor;
515 _c4dbgpf(
"node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
517 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !anchor.begins_with(
'&'));
519 m_curr->ev_data.m_val.anchor = anchor;
524 _c4dbgpf(
"node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
526 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"key cannot have both anchor and ref");
527 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, ref.begins_with(
'*'));
535 _c4dbgpf(
"node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
537 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"val cannot have both anchor and ref");
538 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, ref.begins_with(
'*'));
554 _c4dbgpf(
"node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
556 m_curr->ev_data.m_key.tag = _transform_directive(tag, &m_key_tag_buf);
560 _c4dbgpf(
"node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
562 m_curr->ev_data.m_val.tag = _transform_directive(tag, &m_val_tag_buf);
574 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, directive.begins_with(
'%'));
575 if(directive.begins_with(
"%TAG"))
577 const id_type pos = _num_tag_directives();
579 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"too many directives");
580 if(C4_UNLIKELY(!m_tag_directives[pos].create_from_str(directive)))
581 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"failed to add directive");
583 else if(directive.begins_with(
"%YAML"))
585 _c4dbgpf(
"%YAML directive! ignoring...: {}", directive);
586 if(C4_UNLIKELY(m_has_yaml_directive))
587 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"multiple yaml directives");
588 m_has_yaml_directive =
true;
592 _c4dbgpf(
"unknown directive! ignoring... {}", directive);
605 const size_t sz = m_arena.
size();
606 csubstr prev = m_arena;
610 if(curr.str != prev.str)
611 _stack_relocate_to_new_arena(prev, curr);
617 csubstr prev = m_arena;
618 if(!prev.is_super(*relocated))
619 return alloc_arena(len);
620 substr out = alloc_arena(len);
622 if(curr.str != prev.str)
623 *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
638 _buf_ensure_(m_stack.size() +
id_type(1));
640 m_curr->ev_data = {};
641 _c4dbgpf(
"pushed! level={}", m_curr->level);
647 _buf_flush_to_(m_curr->level, m_parent->level);
651 template<type_bits bits> C4_ALWAYS_INLINE
void _enable__() noexcept
653 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type | bits);
655 template<type_bits bits> C4_ALWAYS_INLINE
void _disable__() noexcept
657 m_curr->ev_data.m_type.type =
static_cast<NodeType_e>(m_curr->ev_data.m_type.type & (~bits));
659 template<type_bits bits> C4_ALWAYS_INLINE
bool _has_any__() const noexcept
661 return (m_curr->ev_data.m_type.type & bits) != 0;
664 void _mark_parent_with_children_()
667 m_parent->has_children =
true;
670 EventSink& _buf_() noexcept
672 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_curr->level < m_val_buffers.
size());
673 return m_val_buffers[m_curr->level];
676 EventSink& _buf_(
id_type level) noexcept
678 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, level < m_val_buffers.
size());
679 return m_val_buffers[level];
682 EventSink
const& _buf_(
id_type level)
const noexcept
684 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, level < m_val_buffers.
size());
685 return m_val_buffers[level];
688 static void _buf_flush_to_(EventSink &C4_RESTRICT src, EventSink &C4_RESTRICT dst) noexcept
694 void _buf_flush_to_(
id_type level_src,
id_type level_dst) noexcept
696 auto &src = _buf_(level_src);
697 auto &dst = _buf_(level_dst);
698 _buf_flush_to_(src, dst);
701 void _buf_flush_() noexcept
703 _buf_flush_to_(_buf_(), *m_sink);
706 void _buf_ensure_(
id_type size_needed) noexcept
708 if(size_needed > m_val_buffers.
size())
709 m_val_buffers.
resize(size_needed);
712 C4_ALWAYS_INLINE
void _send_(csubstr s) noexcept { _buf_().append(s); }
713 C4_ALWAYS_INLINE
void _send_(
char c) noexcept { _buf_().append(c); }
715 void _send_key_scalar_(csubstr scalar,
char scalar_type_code)
720 _send_(scalar_type_code);
724 void _send_val_scalar_(csubstr scalar,
char scalar_type_code)
729 _send_(scalar_type_code);
734 void _send_key_props_()
739 _send_(m_curr->ev_data.m_key.anchor);
743 _send_tag_(m_curr->ev_data.m_key.tag);
745 m_curr->ev_data.m_key = {};
748 void _send_val_props_()
753 _send_(m_curr->ev_data.m_val.anchor);
755 if(m_curr->ev_data.m_type.type &
VALTAG)
757 _send_tag_(m_curr->ev_data.m_val.tag);
759 m_curr->ev_data.m_val = {};
762 void _send_tag_(csubstr tag)
764 _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !tag.empty());
765 if(tag.str[0] ==
'<')
778 void _clear_tag_directives_()
780 for(TagDirective &td : m_tag_directives)
783 id_type _num_tag_directives()
const
787 if(m_tag_directives[i].handle.empty())
791 csubstr _transform_directive(csubstr tag, extra::string *output)
798 TagDirective
const& td = m_tag_directives[i];
799 if(td.handle.empty())
801 if(tag.begins_with(td.handle))
805 size_t len = td.
transform(tag, *output, m_stack.m_callbacks);
808 if(tag.begins_with(
"!<"))
812 if(len > output->size())
814 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !retry);
817 output->resize(output->capacity());
820 return csubstr(*output).first(len);
823 if(tag.begins_with(
'!'))
827 _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos,
"tag not found");
835 _RYML_CHECK_BASIC_(m_stack.m_callbacks, !retry);
837 output->resize(result.len);
838 output->resize(output->capacity());
857 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)